Javascript im Frontend
be Dynamic YAML Templates
Ein Designprinzip des be Portals ist eine umfassende, individuell konfigurierbare Anpassbarkeit. Damit kann das be Portal an die Anforderungen und Bedürfnisse des Benutzers angepasst werden, ohne den Code im Produkt zu ändern. Diese Anpassbarkeit spiegelt sich auch in der Konfiguration, den Pages und Workflows wider.
Dynamische YAML-Konfiguration im Frontend erfolgt über YAML und JavaScript und kann für viele Felder genutzt werden. Zu beachten ist, dass das Ergebnis des JavaScript dem Werteschema des Feldes entspricht.
Nutzung im YAML Format
Die dynamischen Elemente im Schema werden über script_or_<type> Definitionen im YAML Schema beschrieben.
$expr
Ein JavaScript Ausdruck (expression), welches den Wert der Eigenschaft dynamisch zur Laufzeit berechnet.
Der JavaScript Code kann über die Variable $ auf Kontextdaten zugreifen.
Beispiele:
`Berechneter` + ` Text``Wert: ` + $.variables.custom_var
$statement
Ein JavaScript-Code, der den Wert der Eigenschaft dynamisch zur Laufzeit berechnet.
Der JavaScript-Code muss den Wert per return zurückgeben.
Der JavaScript-Code kann über die Variable $ auf Kontextdaten zugreifen.
Beispiele:
return `Berechneter` + ` Text`return `Wert: ` + $.variables.custom_proc_var
$script
Ein JavaScript-Code, der in der Regel durch eine Aktion ausgelöst wird (bspw. Button → Klick-Event, EntityGrid → onLoaded-Event).
Der JavaScript-Code kann beliebige Aktionen ausführen, wie z.B. Variablenzuweisungen oder Backend-Aufrufe.
Der JavaScript-Code kann über die Variable $ auf Kontextdaten zugreifen.
Beispiele:
$.variables.var1 = 'Hello World';backend.execute($.variables.backendAction);
Variablenzuweisungen werden innerhalb eines $script synchron durchgeführt. Erst nach dem letzten Ausdruck innerhalb dieses $script erfolgt jedoch das “Speichern” der Variablenänderungen (wodurch z.B. abhängige Controls aktualisiert werden).
Wenn Variablenänderungen schon während der $script-Ausführung gespeichert werden sollen, ist der Aufruf von await $.controller.flush(); erforderlich.
Außerdem werden innerhalb eines $script Variablen vom Typ entityInstance nicht automatisch aktualisiert, wenn sich bspw. deren primaryKey ändert. Dies passiert erst nach vollständig $script-Ausführung oder nach einem await $.controller.flush()-Aufruf. Wenn die EntityInstance jedoch schon innerhalb des $script aktualisiert werden soll, kann dies mit dem Aufruf von await $.controller.refreshEntityInstance('<entityInstanceName>') erreicht werden.
Kontext Objekte
Der JavaScript-Code bekommt beim Aufruf einen Kontext übergeben. Dieser Kontext stellt den aktuellen Zustand der be Portal Oberfläche für das Skript dar, während es ausgeführt wird. Der Kontext hat klar definierte Eigenschaften und enthält auch einige Hilfsfunktionen, die bei der Ausführung des Skripts verwendet werden können.
Innerhalb des Kontexts werden verschiedene Klassen von Objekten zur Verfügung gestellt. Allgemein gibt es das GenericContextObject, sowie spezielle Klassen auf Basis von YAML Objekten, die mit Hilfsfunktionen zum Auslesen der YAML Informationen angereichert werden.
Der JavaScript Code kann über die Variable $ auf Kontextdaten zugreifen. Verfügbare Kontextdaten sind: 
$.pageId$.loginUser(Information des eingeloggten Users)$.users(User-bezogene Funktionen)$.format(Formatierungsfunktionen)$.variables(im Fall einer Page mit definierten Variablen)$.controller(im Fall einer JavaScript-Ausführung per$script)$.event(im Fall eines ausgelösten Events)$.processVariables(im Fall eines Workflow Formulars)$.tableRowContext[deprecated] (hier stehen die Werte der aktuellen Tabellenzeile zur Verfügung)$.dataSet(hier stehen die Werte der aktuellen Tabellenzeile zur Verfügung)$.ocrData(im Fall eines durch OCR analysierten PDF-Dokuments im Eingangsrechnungsworkflows)$.workflow(Workflow-spezifische Funktionen)$.dialog(Funktionen für das Management von Sub-page Modals)$.customControl(Zugriff auf die iFrames vonCustomControlsfür die Kommunikation mit diesen)$.debug(Hilfs-Funktionen zum debuggen)$.notify(Funktionen zum Anzeigen von Toasts)$.command(Funktionen zum Ausführen von Commands)$.backend(Funktionen zum Ausführen von beas Backend Skripten)$.isMobile(Hilfs-Funktion um herauszufinden ob man sich auf einem mobilen Device befindet)$.expertModeEnabled()(Funktion um herauszufinden, ob der Expertenmodus aktiviert ist)$.navigation$.documents$.focus(Funktionen für die TabKey-Steuerung)
pageId
ID der Page durch welche das JavaScript ausgeführt wird im Format:
<Package-Key>.<PageId>:<Unique-Identfifier>
Der Identifier wird zur Laufzeit erstellt, damit mehrere Page Instanzen mit der gleichen ID unterschieden werden können.
Beispiel:
id: BSP.beispiel-page
controls:
  - controlType: button
    label: Zeige Page ID
    events:
      click:
        $script: |
          debug.log($.pageId);
loginUser
Informationen zum eingeloggten User
Eigenschaft  | Beschreibung  | 
|---|---|
  | Anzeigename des Benutzers  | 
  | E-Mail Adresse aus dem Personalstamm  | 
  | Array von Gruppen IDs zu welchen der Beutzer zugeordnet ist  | 
  | Array von Rollennamen zu welchen der Beutzer zugeordnet ist  | 
  | 
  | 
  | Datensatz ID im Personalstamm  | 
  | Eindeutiger Benutzerschlüssel. 
 
 ID des jeweiligen Datensatzes  | 
Methode  | Beschreibung  | 
|---|---|
  | Gibt an ob der Benutzer zu einer Rolle gehört. Der Vergleich erfolgt   | 
  | Gibt an ob der User   | 
  | Gibt an ob der User   | 
  | Gibt ein Array von Package Rollen zurück, zu denen Der User gehört. Der Vergleich erfolgt   | 
Beispiel:
controls:
  - controlType: button
    label: Zeige Login User
    events:
      click:
        $script: |
          $.debug.log($.loginUser);
          $.debug.log($.loginUser.isPackageAdmin('ERU'));
          $.loginUser.packageRoles('ERU').forEach(role => $.debug.log(role));
users
Über $.usersstehen Hilfsfunktionen für den Umgang mit User-Daten bereit. Nachfolgende Funktionen sind darin enthalten.
Methoden  | Beschreibung  | 
|---|---|
  | Gibt den dem   | 
Beispiel:
controls:
  - controlType: button
    label: Zeige Login User
    events:
      click:
        $script: |
          debug.log($.users.keyToName('U65'));
          debug.log($.users.keyToName($.loginUser.userKey));
format
Über $.format stehen Formatierungsfunktionen bereit. 
Methode  | Beschreibung  | 
|---|---|
  | Der  Optional können  
        JS
     
    
Weitere Optionsmöglichkeiten werden im Unterpunkt “mögliche Optionen” beschrieben.  | 
  | Der  Optional können  
        JS
     
    
Weitere Optionsmöglichkeiten werden im Unterpunkt “mögliche Optionen” beschrieben.  | 
  | Der  Optional können  
        JS
     
    
Weitere Optionsmöglichkeiten werden im Unterpunkt “mögliche Optionen” beschrieben.  | 
  | Der  Wurde der Parameter   | 
Beispiel:
controls:
  - controlType: button
    label: Zeige Login User
    events:
      click:
        $script: |
          const now = new Date(); // 24.05.2024 - 13:05:23 Uhr
          debug.log($.format.date(now)); // Ausgabe: "24.05.24"
          debug.log($.format.datetime(now)); // Ausgabe: "24.05.24, 13:05:23"
          debug.log($.format.time(now)); // Ausgabe: "13:05:23"
          // mit Optionen:
          debug.log($.format.datetime(now, {weekday:'long',
                                            year:'numeric',
                                            month:'long',
                                            hour12:true}));
          // Ausgabe: "Freitag, 24. Mai 2024 um 1:05:23 PM"
mögliche Optionen:
Bei den $.format - Methoden date, datetime und time ist es möglich options optional bei der Erstellung mitzugeben. Diese options müssen als Objekt definiert werden und können folgende Parameter mit folgenden Werten enthalten: 
year - Repräsentation des Jahres - mögliche Werte: 'numeric' und '2-digit'
month - Repräsentation des Monats- mögliche Werte: 'numeric', '2-digit', 'long', 'short', 'narrow'
day - Repräsentation des Tages- mögliche Werte: 'numeric' und '2-digit'
hour - Repräsentation der Stunde - mögliche Werte: 'numeric' und '2-digit'
minute - Repräsentation der Minute - mögliche Werte: 'numeric' und '2-digit'
second - Repräsentation der Sekunde - mögliche Werte: 'numeric' und '2-digit'
Weitere Optionen sind in der offiziellen Mozilla-Dokumentation zu finden: Parameter DateTimeFormat
variables
Die Variablen einer Page können über den Javascript-Kontext gelesen und geschrieben werden. Im Beispiel wird eine Variable matchcode mit dem Wert TOPF_B1 vorbelegt. 
Im Input kann der Matchcode angepasst werden und per Button-Klick wird der Name in der Debug-Konsole ausgegeben. Mit dem Löschen-Button wird der Matchcode auf einen leeren String gesetzt.
# article.page.yml
data:
  variables:
    matchcode:
      type: string
      value: TOPF_B1
controls:
  - controlType: input
    type: text
    value:
      $bind: matchcode
  - controlType: button
    label: Zeige Matchcode
    events:
      click:
        $script: |
          debug.log($.variables.matchcode);
  - controlType: button
    label: Lösche Matchcode
    color: danger
    events:
      click:
        $script: |
          $.variables.matchcode = '';
controller
Der $.controller-Kontext steht in $script-Codes bereit und unterstützt bei der Steuerbarkeit von Asynchronität. 
Methode  | Beschreibung  | 
|---|---|
  | 
  | 
  | 
  | 
  | Gibt zurück, ob die Ausführung des synchronen   | 
Beispiel:
Anzeige des Feldes bez1 zur einer artnr mit Lade-Text (während die Daten geladen werden) und Benachrichtigung (sobald die Daten geladen wurden)
data:
  variables:
    artnr:
      type: string
      value: TOPF_B1
    article:
      type: entityInstance
      source: odata
      entity: Dab010
      primaryKey:
        $bind: artnr
    loadingText:
      type: string
controls:
  - controlType: text
    value:
      $bind: loadingText
  - controlType: input
    type: text
    value:
      $bind: artnr
  - controlType: text
    value:
      $bind: article.bez1
  - controlType: button
    label: Artikel TOPF_B2
    events:
      click:
        $script: |
          $.variables.loadingText = 'Lade Daten...';
          await $.controller.flush(); // notwendig, damit die Variablenänderung gespeichert und der Lade-Text im Control angezeigt wird
          $.variables.artnr = 'TOPF_B2';
          // $.variables.article.bez1 hätte hier noch den Wert der vorherigen artnr (TOPF_B1)
          await $.controller.refreshEntityInstance('article');
          // $.variables.article.bez1 hat hier den neuen Wert
          notify.success('Artikel TOPF_B2 hat die Bezeichnung ' + $.variables.article.bez1);
          $.variables.loadingText = '';
          // $.controller.flush() ist hier nicht notwendig, da es am Ende des $script automatisch ausgeführt wird
event
Eigenschaften  | Beschreibung  | 
|---|---|
  | Eindeutige, intern vergebene ID des Oberflächen Controls  | 
  | Eindeutige Page ID  | 
Je nach Event hat das Objekt weitere Eigenschaften.
beforeValueChanged / afterValueChanged
Eigenschaften  | Beschreibung  | 
|---|---|
  | Wert der Variablen vor der Änderung  | 
  | Wert der Variablen nach der Änderung  | 
  | Name der Variable die sich geändert hat.  | 
processVariables
processVariables sind das gleiche wie variables mit dem Unterschied, dass diese Variablen vom Prozess definiert werden und nicht von der Page.
tableRowContext
[DEPRECATED]: Der tableRowContext ist veraltet, sodass eine einwandfreie Funktionsweise nicht mehr garantiert ist. Stattdessen sollte dataSet (Javascript im Frontend | dataSet) verwendet werden.
Der tableRowContext ist genauso aufgebaut wie die Prozessvariablen. Es ist jedoch ein Objekt mit allen Spalten als Eigenschaften und dem Zelleninhalt als Wert. Folgende Tabelle:
| Name | City | Amount |
------------------------
| Max | Ulm   | 1337   |
sieht im Kontext so aus:
$ = {
  tableRowContext: {
    Name: {
      type: "Text",
      value: "Max"
    },
    City: {
      type: "Text",
      value: "Ulm"
    },
    Amount: {
      type: "Amount",
      value: 1337
    }
  }
}
dataSet
Bei Listen-Controls existiert bei bestimmten Eigenschaften ein dataSet-Objekt, um datensatzspezifische Skripte schreiben zu können. Dieses Objekt enthält die Felder des jeweiligen Datensatzes.
Folgende Tabelle:
| Name | City   | Amount |
------------------------
| Max  | Ulm    |  1337  |
| Tim  | Berlin |  4711  |
sieht im zeilenspezifischen Kontext (z.B. beim Highlighting) so aus:
// Zeile 1:
$ = {
  dataSet: {
    Name: "Max",
    City: "Ulm",
    Amount: 1337
  }
}
// Zeile 2:
$ = {
  dataSet: {
    Name: "Tim",
    City: "Berlin",
    Amount: 4711
  }
}
ocrData
Das ocrData Objekt steht im Kontext zur Verfügung, wenn es die Prozessvariable std_proc_be_ocr_result gibt.
interface OcrContextObject {
    [propertyName: string]: any;
    isAvailable(): boolean;
    formatConfidence(propertyName: string): string;
}
Der ocrData Kontext enthält alle Properties die hier (https://businessexpress.cloud/docs/be-documents-service/latest/index.html) definiert sind, sofern sie von der OCR Erkennung erkannt wurden. 
Es gibt außerdem die Methode isAvailable(), mit der geprüft werden kann, ob das OcrContextObject Eigenschaften enthält und die Methode formatConfidence(), mit der die Confidence der übergebenen Property als formatierten String zurückgegeben wird, z. B. 0.87 -> 87 %
Beispiel:
$.ocrData = {
  total: {
    value: 1378.37,
    rawValue: "1378,37 €",
    confidence: 0.86,
  },
}
$.ocrData.isAvailable();             // = true
$.ocrData.formatConfidence('total'); // = '86.0 %'
workflow
$.workflow steht auf Pages zur Verfügung, die Teil eines Workflows sind.
ocrData: OcrContextObject;
complete: () => Promise<void>;
completeWithVariables: (variables: Record<string, any>) => Promise<void>;
error: (errorCode: string) => Promise<void>;
escalate: (escalationCode: string) => Promise<void>;
saveVariable: (variableName: string) => Promise<void>;
setNextUser: (userKey: string) => Promise<void>;
setNextGroups: (groupKeys: string[]) => Promise<void>;
userAssignment: (definition: Partial<UserAssignmentDefinition>, callback: () => void) => void;
confirmation: (definition: Partial<ConfirmationDefinition>, callback: () => void) => void;
isAssignedToMe: () => boolean;
assignedUser: () => string;
Methoden  | Beschreibung  | 
|---|---|
  | Schließt den aktuellen Workflow-Schritt ab  | 
  | Schließt den aktuellen Workflow-Schritt ab. Es kann ein   | 
  | Löst für den aktuellen Workflow-Schritt den Fehler mit dem übergebenen Fehlercode aus.  | 
  | Löst für den aktuellen Workflow-Schritt die Eskalation mit dem übergebenen Eskalations-Code aus.  | 
  | Speichert die angegebene Page-Variable sofort in Camunda ab. Sofern die Variable in Camunda nicht existiert, wird sie erstellt.  | 
  | Kann in   | 
  | Kann in   | 
  | Kann in  
 
  | 
  | Zeigt einen Confirm-Dialog mit der übergebenen Definition an.  
 
  | 
  | Gibt zurück, ob der ausgewählte Task dem aktuell angemeldeten User zugewiesen ist.  | 
  | Gibt für den ausgewählten Task den   | 
Eigenschaften  | Beschreibung  | 
  | Siehe Beschreibung   | 
dialog
Erlaubt die Nutzung von Sub-Page Modals.
Beispiel:
controls:
  - controlType: button
    label: btn
    events:
      click:
        $script: |
          $.dialog.show(
            'PKG.page',
            (event) => {debug.log(JSON.stringify(event));}, 
            {size: 'medium', 'title' : 'hello world'});
 
Dies erzeugt ein Modal, dass die Page PKG.page. Der callback der hier mitgegeben wird ist relevant für weitere dialog Funktionen die in der entsprechenden subpage benutzt werden können (siehe unten). Zusätzlich hat das Modal eine Toolbar mit Button, die in der aufgerufenen Page definiert werden können. Die Definition von diesen findet innerhalb von contributes statt.
Obige Call Signature ist deprecated (ab 7.7.0). Sie wird ersetzt durch
$.dialog.show({
  pageId: 'SOME.page',
  callback: (event) => $.debug.log(event),
  size: 'large',
  title: 'My super Modal',
  inputs: {
    some_variable: 'I came from outside',
    another_variable: 12
  }
})
Insbesondere können mit der neuen syntax auch Inputvariablen an das Modal übergeben werden, sofern die Variablen als Inputvariablen in der Modalpage definiert sind.
Zum Beispiel:
contributes:
  dialog:
    buttons: 
      - label:
          $expr: |
            $.variables.someLabel + "!";
        color: danger
        disabled:
          $bind: isDisabled
        events:
          click:
            $script: | 
               $.dialog.cancel(), 
      - label: speichern
        color: success
        events:
          click:
            $script: | 
               $.dialog.success({ out: "resultData"})
Dies erzeugt zwei Button in der Toolbar des Modals. Zusätzlich stehen in der Subpage die Funktionen:
$.dialog.cancel(payload), $.dialog.close(payload) und $.dialog.success(payload) zur Verfügung, wobei der payload optional ist. Alle diese Funktionen schließen das Modal und führen den callback der $.dialog.show Funktion aus, wobei
event = {
  resultCode: /* 'close', 'success' or 'cancel' */,
  resultData: payload
}
ist.
customControls
Beispiel:
controls:
  - controlType: custom
    name: myCustomControl
    id: idMyCustomControl
    width: 20vh
    events: 
      receiveMessage:
        $script: |
          debug.log('receive iFrame: ' + $.message);
  - controlType: button
    label: SendStaticMessage
    events:
      click:
        $script: |
          $.customControl('idMyCustomControl').postMessage("Statische Nachricht");
debug
Hilfs Funktionen zum Debuggen
Methoden  | Beschreibung  | 
|---|---|
  | Gibt Nachricht auf der Browser Konsole aus  | 
  | Gibt Nachricht auf der Browser Konsole aus aber nur wenn der Expertenmodus aktiv ist  | 
Beispiel:
controls:
  - controlType: button
    label: Debug Log
    events:
      click:
        $script: |
          $.debug.log('Button Clicked!')
notify
Hilfs Funktionen zum Anzeigen von Toasts
Methoden  | Beschreibung  | 
|---|---|
  | Zeigt grünen Toast an  | 
  | Zeigt roten Toast an  | 
  | Zeigt blauen Toast an  | 
  | Zeigt orangen Toast an  | 
  | Zeigt je nach Typ einen Toast mit entsprechender Farbe an 
 
  | 
Beispiel:
controls:
  - controlType: button
    label: Toasts zeigen
    events:
      click:
        $script: |
          $.notify.success('Erfolgreich');
          $.notify.error('Fehler');
          $.notify.info('Erledgit');
          $.notify.warning('Wenig Speicher');
          $.notify.show('success', 'Erfolgreich');
command
Funktionen zum Ausführen von Commands
Methoden  | Beschreibung  | 
|---|---|
  | Führt das   | 
Beispiel:
pageId: BSP.command-page
commands:
  - name: ExampleCommand
    label: Beispiel Kommande
    action:
      $script: |
        $.debug.log('Beispiel Kommando ausgeführt!')
controls:
  - controlType: button
    label: Kommando ausführen
    events:
      click:
        $script: |
          $.command.execute('BSP.command-page.ExampleCommand')
backend
Funktionen zum Ausführen von beas Backend Skripten
Methoden  | Beschreibung  | 
|---|---|
  | Führt im beas die Funktion mit dem angegebenen Namen aus.  | 
Beispiel:
controls:
  - controlType: button
    label: Einbuchen
    events:
      click:
        $script: |
          $.backend.execute('bdeEinbuchen')
isMobile
Hilfs-Funktion um herauszufinden ob man sich auf einem mobilen Device befindet
Beispiel:
controls:
  - controlType: button
    label: Mobilgerät?
    events:
      click:
        $script: |
          $.debug.log(`Mobil (true/false)? ${$.isMobile}`)
expertModeEnabled
Hilfs-Funktion um herauszufinden, ob der Expertenmodus aktiv ist.
Wenn der Expertenmodus geändert wird, erfolgt sofort eine Aktualisierung des JavaScript-Kontexts.
Beispiel:
controls:
  - controlType: text
    value: Experteninformation nur im Expertenmodus sichtbar
    visible:
      $expr: | # js
        $.expertModeEnabled()
navigation
Funktion zur Navigation zu einer URL.
controls:
  - controlType: button
    events:
      click:
        $script: | # js
          $.navigation.navigate('https://www.google.de/', '_self');
          // $.navigation.navigate('/administration/system-settings');
confirm
Hilfsfunktion zur Erstellung von Confirm-Dialogen.
Methoden  | Beschreibung  | 
|---|---|
  | Erstellung eines Custom-Dialogs mit folgenden Parametern: 
  | 
  | Erstellung eines Default-Dialogs mit “Abbrechen” und “Bestätigen” Button mit folgenden notwendigen Parametern: 
 optionale Parameter: 
  | 
  | Erstellung eines Custom Dialogs mit Eingabefeld. Die Callbacks, die in den Button definiert werden haben hierbei als Argument den Eingabewert.  | 
- controlType: button
  label: Neuen Artikel anlegen
  events:
    click:
      $script: |
        const artikelAnlegen = function(type) {
          $.variables.newArticleType = type;
          $.backend('createArticle');
        }
      
        $.confirm.show(
          'Artikel anlegen', 
          'Welchen Artikel möchten Sie anlegen?', 
          [
            { label: 'Kaufteil', callback: () => artikelAnlegen('T'), type: 'default', stylingMode: 'contained' },
            { label: 'Baugrupppe', callback: () => artikelAnlegen('B'), type: 'danger', stylingMode: 'outlined' },            
            { label: 'Artbeitswert', callback: () => artikelAnlegen('A'), type: 'success', stylingMode: 'text' },
          ], 
          'medium'
        )
        
- controlType: button
  label: Artikel löschen
  events:
    click:
      $script: |
        const articleNumber = $.variables.articleNumber;
        const deleteArticle = function() {
          $.variables.articles.$.delete();
          $.notify.success(`Der Artikel wurde ${articleNumber} gelöscht`);
          $.backend('reorgArticles');
        }
        $.confirm.default(
          'Artikel löschen', 
          `Möchten Sie den Artikel ${articleNumber} wirklich löschen?`, 
          deleteArticle
        )  
documents
Methoden  | Beschreibung  | 
|---|---|
  | Lädt das Dokument mit der angegebenen   | 
Beispiel:
- controlType: button
  label: Download
  events:
    click: 
      $script: |
        $.documents.download($.variables.documentUuid);
messaging
Grundlagen des Messagings: https://dontenwill.atlassian.net/wiki/spaces/BPOH/pages/986841157
Methoden  | Beschreibung  | 
|---|---|
  | Erstellt einen   | 
  | Kurzschreibweise für   | 
MessagingContext:
Methoden  | Beschreibung  | 
|---|---|
  | Versendet eine MQTT-Nachricht in dem als   | 
Beispiel:
- controlType: button
  label: Jump via MQTT for my User and User 'U2'
  events:
    click: 
      $script: |
        $.messaging.user().publish('jump', {'key': 'article', 'id': 123});
        $.messaging.user('U2').publish('jump', {'key': 'article', 'id': 123});
odata
Methoden  | Beschreibung  | 
|---|---|
  | Führt die ungebundene OData Action aus und gibt das Ergebnis zurück. Der   | 
  | Führt die ungebundene OData Funktion aus und gibt das Ergebnis zurück. Die Parameter können als Objekt übergeben werden, wobei der Name des Parameter der Property-Name ist.  | 
  | Führt die OData Action aus und gibt das Ergebnis zurück. Der   | 
  | Führt die OData Action aus und gibt das Ergebnis zurück. Der   | 
  | Führt die OData Funktion aus und gibt das Ergebnis zurück. Die Parameter können als Objekt übergeben werden, wobei der Name des Parameter der Property-Name ist.  | 
  | Führt die OData Funktion aus und gibt das Ergebnis zurück. Die Parameter können als Objekt übergeben werden, wobei der Name des Parameter der Property-Name ist.  | 
Beispiel:
- controlType: button
  label: OData Aktion
  events:
    click: 
      $script: |
        await $.odata.executeAction('NeuberechngungPreise', {articleType: 'A'});
- controlType: button
  label: OData Funktion
  events:
    click: 
      $script: |
        await $.odata.executeFunction('HoechsterPreis', {articleNumber: 'JFK_4747_AKJF'});
executeEntityAction: async (entityName: string, primaryKeyValue: any, actionFQN: string, body: Record<string, any> = null): Promise<any> => {
  const service = StaticInjector.get<ODataMethodsService>(ODataMethodsService);
  return service.executeEntityAction(entityName, primaryKeyValue, actionFQN, body);
},
executeEntityCollectionAction: async (entityName: string, actionFQN: string, body: Record<string, any> = null): Promise<any> => {
  const service = StaticInjector.get<ODataMethodsService>(ODataMethodsService);
  return service.executeEntityCollectionAction(entityName, actionFQN, body);
},
executeFunction: async (functionName: string, params: Record<string, any> = null, namespace: string = 'OData.Beng'): Promise<any> => {
  const service = StaticInjector.get<ODataMethodsService>(ODataMethodsService);
  return service.executeUnboundFunction(functionName, params, namespace);
},
executeEntityFunction: async (entityName: string, primaryKeyValue: any, functionFQN: string, params: Record<string, any> = null): Promise<any> => {
  const service = StaticInjector.get<ODataMethodsService>(ODataMethodsService);
  return service.executeEntityFunction(entityName, primaryKeyValue, functionFQN, params);
},
executeEntityCollectionFunction: async (entityName: string, functionFQN: string, params: Record<string, any> = null): Promise<any> => {
  const service = StaticInjector.get<ODataMethodsService>(ODataMethodsService);
  return service.executeEntityCollectionFunction(entityName, functionFQN, params);
},
clipboard
Enthält Methoden für die Clipboard Api
Methode  | Beschreibung  | 
|---|---|
  | Liest einen String aus der Zwischenablage  | 
  | Schreibt einen String in die Zwischenablage  | 
focus
$.focus enthält Funktionen zur Tabsteuerung:
Methoden  | Beschreibung  | 
|---|---|
  | Fokussierung des nächsten Elements hinsichtlich der definierten   | 
  | Fokussierung des vorherigen Elements hinsichtlich der definierten   | 
  | Fokussierung des Inputfeldes, an dem eine bestimmte Variable gebunden ist. Eine Besonderheit ergiebt sich im Falle von EntityInstanzen. Der Input kann hierbei der voll Pfad zu einer Property sein   | 
  | “Kurzschreibweise”:   | 
  | Erlaubt das manuelle defokusieren um beispielweise Commands via Shortcut aus dem Bearbeitungsmodus zu ermöglichen. Ein Aufruf führt zum flushen der aktuellen Änderungen.  | 
Modularisierung von JavaScript Code
Oft möchte man gleichen Code in mehr als einer Expression verwenden. Dieser Code kann in Module ausgelagert werden, welche automatisch für alle Javascript Elemente einer page zur Verfügung stehen. 
Im folgenden wird beschrieben, wie man Module in einer Page bereitstellt und wie diese Module zu definieren sind.
Modul definieren und verwenden
Ein Modul kann Funktionen, Konstanten und Klassen exportieren. Es wird nicht automatisch alles exportiert, was in dem Modul definiert ist, es muss explizit angegeben werden, welche Teile exportiert werden sollen.
Export von Funktionen:
// Datei: mathUtils.js
const PI = 3.1415;
function square(num) {
  return num * num;
}
function circularArea(radius) {
  return PI * square(radius);
}
// Es wird nur die Funktion circularArea exportiert. 
// square und PI sind in den Expressions also nicht verfügbar.
return { circularArea }
Export von Konstanten und Klassen
// Datei: articleHelper.js
const ArticleNoLength = 20;
class ArticleHelper {
  trimArticleNumber(articleNumber) {
    return articleNumber.substring(0, ArticleNoLength);
  }
}
return { ArticleNoLength, ArticleHelper }
Module brauchen einen Namen, damit diese verwendet werden können. Der Name wird entweder in der Page-Definition angegeben oder leitet sich vom Namen der JS-Datei ab.
- controlType: inputContainer
  controls:
    - controlType: label
      value: "Artikel-Nummer"
    - controlType: input
      type: text
      value:
        $statement: |
          const helper = new articleHelper.ArticleHelper();
          return helper.trimArticleNumber("MUTTER M-1");
Inline Module
JS Module können direkt in einer Page definiert werden. Alle exportierten Funktionen stehen in den Expressions und Statements auf der Page zur Verfügung
import:
  - name: base64
    src: |
      function decode(encoded) {
        return atob(encoded);
      }
      function encode(decoded) {
        return btoa(decoded)
      }
      // Export der Funktionen
      return { decode, encode }
Module in JS Dateien
Wenn Module größer werden oder wenn Sie auf verschiedenen Pages verwendet werden sollen, macht es Sinn, diese in eigene Dateien auszulagern. Der Name der JS Datei ist dabei der Name des Moduls.
Module müssen nicht explizit in Pages importiert werden. Die Verfügbarkeit der Module leitet sich von der Ordner-Struktur des .pages Ordners ab. Ein Modul ist in allen Pages verfügbar, welches sich im gleichen Ordner befindet. Außerdem ist es in allen Pages in Unterordnern verfügbar. 
Im folgenden Beispiel ist das Modul utils auf allen Pages verfügbar. Das Module articleHelper jedoch nur auf der Page article
Projekt Root-Ordner
|
|_ .pages
|____ article
|______ article.page.yml
|______ articleHelper.js
|____ main.page.yml
|____ utils.js
Debugging von Skripten
Skripte, die auf Pages definiert werden oder die aus JavaScript Modulen kommen, können im Browser debugged werden. Es können Breakpoints gesetzt werden, an denen die Ausführen des Programms angehalten wird. Dabei kann der komplette Kontext untersucht werden.
Die Ausführung wird nur angehalten, wenn die DevTools des Browsers geöffnet sind.
Beispiel zum Setzen eins Breakpoints:
controls:
  - controlType: button
    label: Debugging von Skripten
    events:
      click:
        $script: |
          const now = new Date();
          const text = `heutiges Datum: ${now}`;
          debugger; // diese Zeile setzt einen Breakpoint
          $.notify.info(text);
Fehlerhandling von Skripten
Skripte, die auf Pages definiert werden oder die aus JavaScript Modulen kommen, können Kompilierfehler enthalten und somit unbrauchbar werden. Damit Page-Entwickler über derartige Fehler informiert werden, erfolgt eine Evaluierung dieser JavaScripts zu dem String Fehler in der JavaScript-Property!. Darüber hinaus wird der Fehler mit Zusatzinformationen auf der Browser-Konsole ausgegeben, um die Fehlersuche zu vereinfachen.
Beispiel eines fehlerhaften JavaScripts:
controls:
  - controlType: text
    value:
      $expr: |
        'thisIsInvalidJavaScript'{{{}}}
Beispiel-Fehlerausgabe auf der Konsole:
VM2746:56 Custom JavaScript is invalid.
Path: <pageId>.text.value
Error:
 SyntaxError: Unexpected token '{'
    at [...]
Code:
 'thisIsInvalidJavaScript'{{{}}}