Wie schreibe ich eine Komponente¶
Eine Komponente ist eine einfach HTML-Datei die für die Komponenten alle notwendigen Resourcen (Css, Javascript, Templates, ...) enthält und über einen Dokumenten-Import in die Konsole eingebunden wird.
Es gibt zwei Arten von Komponenten: Funktionskomponenten 2 die eine bestimmte Funktionalität innerhalb der Konsole bereitstellen - zum Beispiel Tastaturkürzel - und Kontextkomponenten 1, die eine Ausgabe habe und über die Navigation angesteuert werden - zum Beispiel ein Dashboard.
Der Basisaufbau beider Typen ist identisch. Kontextkomponenten1 verfügen zusätzlich über einen View.
Vorbereitung¶
Als erstes legen wir folgende Verzeichnisstruktur an.
Komponente
┣━━ assets ⤑ Assets wie Bilder, PDF, etc.
┣━━ css ⤑ CSS-Dateien
┣━━ javascript ⤑ Javascriptdateien
┣━━ resource ⤑ Ressourcen wie Sprachdateien
┗━━ vendor ⤑ Herstellerdateien
Der grundlegende Aufbau einer Komponente besteht aus einem einfachen HTML-Gerüst.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Meine Komponenten</title>
</head>
<body>
</body>
</html>
Wir speichern nun diese Datei als HTML-Datei in unser Komponentenverzeichnis.
Komponente
┗━━ component.html ⤑ Komponentendatei
Nun haben wir eine Komponente und können diese je nach Typ über die Konfiguration in die Konsole einbinden.
Beispiel für das Einbinden eine Funktionskomponente 2
"module": [
{
"component": "MyComponent",
"location": "http://www.example.com/component.html"
}, ...
],
Und ein Beispiel für die Konfiguration einer Kontextkomponente 1
"components": {
"component": [
{
"module": {
"prototype": "MyComponent",
"location": "http://www.example.com/component.html"
},
"handler": "mycomponent",
"arguments": {
"key": 'value
}
}, ...
Die Kontextkomponente verfügt in der Konfiguration über einen Schlüssel zur Angabe des Handlers und einen Schlüssel zur Angabe von zusätzlichen Argumenten. Dadurch lässt sich eine Komponente mehrfach nutzen.
Komponenten in Javascript definieren¶
Jede Komponente wird über das Modulsystem vom Host eingebunden.
Innerhalb der Komponente legen wir ein zentrales Komponenten-Objekt
an. Dies wird in der HTML-Datei definiert. Hierzu wird unser Beispiel um ein script
-Bereich erweitert.
<script>
var component = Alvine.Package.Factory.createComponent('MyComponent');
</script>
Bei einer Kontextkomponenten1 wird beim Verlassen des Kontextes die Methode MyComponent.cleanUp()
aufgerufen. In dieser
Methode sollten alle Ressourcen (Registry, Datenbank, ..) die von der Komponente verwendet werden, geschlossen und
gelöscht werden.
component.cleanUp = function() {
// Aufräumarbeiten
};
Kontextkomponente definieren¶
eine Kontextkomponete stellt die Schnittstelle zwischen dem System und den benutzer her. Dafür benötigt die Komponente einen View (Darstellung der Steuerelemente). Für den View wird eine Struktur benötigt, die wir über ein Template in die Komponente einbinden.
Die erfolgt im <head>
Bereich der HTML-Datei der Komponente. Das Template muss das Attribut data-container
enthalten.
Innerhalb dieser Node wird die Ausgabe der Komponente eingefügt.
<template id="template">
<div data-container></div>
</template>
Über die Methoden Alvine.Package.Factory.createComponent(componentName, componentVersion, requirements)
und Component.createView()
lässt sich die Komponente anschliessend initialisieren. Leichter und einfacher geht es aber über die Methode Alvine.Package.Factory.startComponent(componentName, componentVersion, requirements)
.
Die Methode Alvine.Package.Factory.startComponent(componentName, componentVersion, requirements)
fügt alle Bausteiner zusammen und erlaubt so eine schnelle
und sichere Umsetzung einer Komponente. Alvine.Package.Factory.startComponent(componentName, componentVersion, requirements)
erwartet neben dem
Namen der Komponente auch die Version und optional Abhängigkeiten.
Alvine.Package.Console.Host.startComponent(namespace+'.'+componentName, componentVersion, {
libraries: {
alvine: DEFAULTS.REQUIREDALVINEFRAMEWORKVERSION,
jquery: DEFAULTS.REQUIREDJQUERYVERSION
},
externals: [
/** "//cdnjs.cloudflare.com/ajax/libs/dexie/2.0.4/dexie.js",
"/app/console/js/platform.js",
"/app/console/js/platform/workingcopy.js",
"/app/console/js/platform/locale.js",
"/app/console/js/platform/net.js",
"/app/console/js/platform/lists.js",
"/app/console/js/platform/maps.js",
"/app/console/js/platform/registry.js",
"/app/console/js/platform/lists.js",
"/app/console/js/platform/form.js",
"/app/console/js/platform/persistence/index.js",
"/app/console/js/platform/persistence/indexeddb/dexie/objectstore.js",
"/app/console/js/platform/persistence/indexeddb/dexie/dataobject.js",
"/app/console/js/platform/persistence/indexeddb/dexie/datasource.js",
"/app/console/js/platform/persistence/indexeddb/dexie/query.js",
"/app/console/js/platform/persistence/indexeddb/dexie/queryparser.js",
"/app/console/js/platform/form/dialog.js",
"/app/console/js/platform/form/detailform.js",
"/app/console/js/waiterfy/listdialog.js",
"/app/console/js/platform/model.js",
"/app/console/js/platform/model/commerce/item/catalog/category.js",
"/app/console/js/platform/datamanager.js",
"/app/console/js/platform/storagemanager.js",
"/app/console/js/platform/queryparser.js",*/
],
modules: {
'Alvine.Package.UI.Dialog.Bootstrap': '1.0.0',
'Alvine.Package.UI.Dialog.Widgets': '1.0.0',
'Alvine.Package.i18n.Globalize': '1.0.0'
},
locales: [
DEFAULTS.RESOURCEPATH+"/"
],
component: {
cleanUp: (a) => {
if(view.dialog) {
view.dialog.cleanUp();
}
}
},
view: {
init: initUI,
activate: activateUI,
template: '#template'
}
}).then(data => {
view = data[1];
}).catch(error => {
Alvine.Package.Console.Host.showNothingWorksAnymoreDialog(namespace, 'Alvine.Platform.Console.Order.List.startComponent', error);
});
Die beiden Funktionen initUI
und activateUI
werden nacheinander aufgerufen. Während des Aufrufs
von initUI
werden alle Controls
und Dialoge erstellt und nach aufruf der Funktion ins DOM eingebunden.
Nachdem das DOM erstellt wurde, wird von createView
der Callback activateUI
aufgerufen. Hier können
Eventhandler und Änderungen am DOM durchgeführt werden.
Bilder und CSS-Dateien¶
Bilder werden im Verzeichnis asset
und CSS-Dateien im Verzeichnis css
der Komponente gespeichert. Die
Dateien können relativ zur Komponente referenziert werden.
<link rel="stylesheet" href="css/my.css">
4d3c02eb-8976-4388-9406-06b447f19890
<img src="asset/image/my.png">
Javascript¶
Javascript kann direkt in der HTML-Datei der Komponente definiert werde. Alternativ kann es in eigenen Dateien ausgegliedert und relativ eingebunden werden.
<script src="javascript/my.js"></script>
Externe Bibliotheken¶
Dateien von externen Projekten werden entweder direkt über ein CDN eingebunden oder im vendor-Verzeichnis der Komponente gespeichert.
Laden der lokalisierten Sprachdatei¶
Alle Übersetzungen der Komponente werden in einer einfachen JSON-Datei gespeichert. Der Aufbau der Datei ist sehr einfach. Die Schlüssel entsprechen den in der Komponente verwendeten Zeichenketten und der Wert ist jeweils die Übersetzung in der betreffenden Landessprache.
{
"i18n:ok": "OK",
"i18n:cancel": "Abbruch",
}
Hinweis
Die Schlüssel von lokalisierten Texten sollten immer mit dem Prefix i18n:
beginnen.
Die Lokale-Datei kann absolut oder relativ zur Komponente - am besten im Verzeichnis resource
gespeichert werden. Der Dateiname ist der Name der Lokale, zum Beispiel: de-DE.json oder nur de.json.
resource
┣━━ de.json ⤑ Deutsche Sprachdateien
┗━━ en.json ⤑ Englische Sprachdateien
Einfache Ausdrücke wir die folgenden sind bereits über die Bootstrap-Komponente verfügbar und müssen nicht neu definiert werden.
"i18n:ok": "OK",
"i18n:cancel": "Abbruch",
"i18n:submit": "absenden",
"i18n:delete": "löschen",
"i18n:add": "hinzufügen",
"i18n:remove": "entfernen"
Wichtig
Alle Schlüssel werden in einer zentralen Datenbank des Host gespeichert. Die eigenen Schlüssel sollten deshalb immer im
Namensraum der Komponente definiert werden, damit diese keine anderen Schlüssel überschreiben. Statt i18n:mykey
sollte
i18n:mycomponent.mykey
definiert werden.
Die Sprachdatei kann in der Komponente über folgende Anweisung geladen werden:
var baseurl = component.getModule().getBaseURL();
var resourcePath = 'resource';
var promise = Alvine.Package.Console.Host.loadLocale(baseurl+resourcePath);
promise
.then(function(result) {
// Lokale wurden geladen
})
.catch(function(result) {
// Fehler
});
Das von Host.loadLocale zurückgegebene Promise transportiert als ersten Wert ein Objekt mit dem Status der Queue. Im Erfolgsfall
wird {state:'done'}
und im Fehlerfall {state:'error'} zurückgegeben.
Siehe hierzu auch die Anleitung im Alvine Frontend Framework
Zugriff auf die Settings¶
Speichert die Komponente Werte im Settingsbereich, so kann die Komponente auf diese über die Registry zugreifen.
Alvine.Registry.getValueFromPath('console.settings.my');