Activate JS ist eine JQuery basierende Templating Engine.
Ein Control-Attribut besteht aus einem JSON-String, der ein oder mehrere Paare aus Control-Name und Control-Wert enthält {<control-name>: <control-value>, ...}.
Die Control-Werte bestehen aus Javascript und werden erst zum jeweiligen Zeitpunkt das Ausführens evaluiert. Dies bedeutet insbesondere, dass ein Control auch auf Werte zugreifen kann, die von vorherigen Controls desselben Control-Attributs erzeugt wurden.
<div control="{apply: $.fn.Panel}"> <div>Header</div> <div>Content</div> </div>
Erklärung: Das Attribut "control" enthält JSON-Code, der ein oder mehrere Key-Value-Paare enthalten kann. Jeder Key ist einem Control aus $.controls zugeordnet. Im obigen Beispiel also der Key apply ruft $.controls.apply auf. This entspricht dabei dem JQuery-Element des Elements. Verwendet man die Bridge eines JQuery-Widgets, wie etwa $.fn.Panel, wird das JQuery-Widget instantiiert.
<div control="{template: 'some-panel', apply: $.fn.Panel}" style="margin-top: 10px;"> <div>Template Header</div> </div>
<div control="{applyTemplate: 'some-panel'}"> <div>Individual Content 1</div> </div>
<div control="{template: 'some-panel', apply: $.fn.Panel}" style="margin-top: 10px;"> <div>Panel Template</div> <div control="{insert: 'content'}"/> </div> <div control="{applyTemplate: 'some-panel'}"> <div control="{define: 'content'}">Individual Content 2</div> </div>
Erklärung: Das Element (div) mit dem Control applyTemplate wird durch das Template mit dem Namen "some-panel" ersetzt. Dabei werden alle Controls des Templates angewendet, zusätzlich zu den einfügenden Element.
<div control="{for: {begin: 0, end: 3, variable: 'index'}}"> <div control="{interpolate: true}">Count: {index}</div> </div>
<div control="{for: {list: this.someList, variable: 'element'}}"> <div control="{interpolate: true}">Element: {element}</div> </div>
<div control="{for: {list: this.someObject, variable: 'value'}}"> <div control="{interpolate: true}">Key: {index}, Value: {value}</div> </div>
<div control="{for: {begin: 0, end: 3, variable: 'x'}}"> <div control="{interpolate: true}">Iteration No. {x}</div> </div>
<form id="form"> <div control="{id: 'text'}">Some Text</div> </form>
Ergebnis: Das innere div-Element erhält das Attribut id="form:text".
Ein beliebter Kunstgriff ist, Teile der Page zunächst mit dem Style display oder visibility unsichtbar zu machen und erst nach fertiger Aktivierung anzuzeigen:
<div style="display: none;" control="{id: 'activate-test', after: {css: {display: 'block'}} }"> [...] </div>
<div style="display: none;" control="{id: 'activate-test', after: {css: {display: 'block'}} }"> [...] </div>
Erklärung: Es handelt sich um dasselbe Beispiel wie bei dem Control style, jedoch geht es hier um den Aspekt after. Das Control after enthält als Wert wieder eine Liste von Controls, die nach der Aktivierung der Children ausgeführt werden.
<div control="{applyTemplate: 'some-panel', set: {templateParam: 2}}"> <div control="{define: 'content'}">Individual Content 2</div> </div> <div control="{template: 'some-panel', apply: $.fn.Panel}" style="margin-top: 10px;"> <div control="{interpolate: true}">Panel Template, Parameter: {templateParam}</div> <div control="{insert: 'content'}"/> </div>
Erklärung: Der Parameter templateParam wird von der Einfügestelle applyTemplate an das Template selbst übergeben. Das heißt, jede Template-Instanz kann einen unterschiedlichen Wert erhalten.
<div control="{if: test == 2, css: {color: '#10a010'}}">Some Text</div>
Hinweis: Die If-Condition wird während des Parsens des Javascript-Code ausgeführt, was in vielen Fällen zu früh sein kann.
Um auf Ergebnisse anderer Controls zugreifen zu können, kann die Condition auch eine Funktion sein:
<div control="{if: this.test == 2, css: {color: '#10a010'}}">Some Text</div>
<label control="{rendered: this.type != 'input'}">Input</label>
<div control="{ajax: {url: 'http://localhost/test', variable: 'data'}, interpolate: true}">{data}</div>
Erklärung: Es wird ein AJAX-Request durchgeführt und das Ergebnis in der Variable data gespeichert. Das nachfolgende Interpolation-Control fügt den Text in den Tag-Content ein.
Die möglichen AJAX-Control Parameter:
Parameter | Bedeutung |
---|---|
method | HTTP Method, die verwendet wird, wohl hauptsächlich GET oder POST |
URL | Die URL, die für den AJAX-Request benutzt wird |
data | Die Query/Post-Parameter für den AJAX-Request |
variable | Die Variable in der das Ergebnis gespeichert wird |
<div control="{text: this.someVariable}"/>
<tr control="{for: {list: this.rows, variable: 'row'}, async: 1000 * Math.random(), after: {css: {visibility: 'visible'}} }" style="visibility: hidden;"> [...] </tr>
Erklärung: Das Async-Control ermöglicht ein synchrones Rendern jeder TR-Row, die durch die vorhergehende For-Schleife erzeugt wurde. Jede Zeile ist zunächst unsichtbar (visibility) und wird nach dem Rendern auf visible gesetzt.
<input control="{bind: this.node.value}"/>
$.controls.myControl = function(next) { this.element.text("Hello World!"); next(); };
Hinweis: Ein Control hat immer den Parameter next, der in der Regel am Ende aufgerufen wird. Dieser sorgt dafür, dass die nachfolgenden Controls und damit auch untergeordnete Elemente aktiviert werden.
Bei mehreren Controls kann man die bequemere Variante mit QUuery extends verwenden:
$.controls.extend({ myControl: function(next) { this.element.text("Hello World!"); next(); }, myControl2: function(next) { this.element.text("Second Control!"); next(); } });
Im Aufruf des Controls wird this auf den aktuellen Context gesetzt.
Key | Beschreibung |
---|---|
element | Das aktuelle JQuery-Element in dem der Funktionsaufruf stattfindet. |
controls | Die aktuelle Control-Struktur, die gerade abgearbeitet wird. |
control | Der aktuelle Control-Entry, der gerade verarbeitet wird. Er besteht aus key (Name) und value (Javascript). |
root | Zugriff auf dem Root-Context. Kann für Templates und andere globale Variablen verwendet werden. |
prefix | Das aktuelle Prefix des aktuellen Id-Attributs. Dies besteht aus den Id's der übergeordneten Elemente, getrennt durch Doppelpunkte. |
Der Context enthält auch eine Reihe von Funktionen, die für das Implementieren eines Controls nützlich sein können:
Funktion | Beschreibung |
---|---|
pop() | Holt das nächste Control aus der aktuellen Control Execution Chain. Das Control ist damit dauerhaft entfernt und wird nicht mehr durch den Aufruf von next() ausgeführt. |
activate(element, options) | Aktiviert die Controls an einem Element und deren Unterknoten. Normalerweise wird diese Funktion durch den Aufruf von next() automatisch ausgeführt. Programmatisch erzeugte Elemente, wie bei Iterationen, können einen expliziten Aufruf erfordern. |
interpolate(text) | Liefert den übergebenen Text, alle Variablen werden durch ihre Werte ersetzt. |
resolve(expression) | Liefert den Wert einer Variable zurück. |
warn(message) | Gibt eine Warnung auf der Konsole mit entsprechenden Kontext-Informationen und Aufrufstack aus, um Fehler leichter lokalisieren zu können. |
clone | Diese Funktion erzeugt einen untergeordneten Context. Sie wird in der Regel intern aufgerufen, wenn ein Child-Element im HTML-Tree verarbeitet wird. |
replace | Damit ist das konforme Ersetzen des eigenen HTML-Elements möglich. Schleifen, Bedingungen und andere dynamische Elemente ersetzen oft das eigenen Element mit dieser Funktion. |
getControls | Liefert die uncompilierte Liste der im Control-Attribut enthaltenen Controls in der Form eines Javascript-Objects zurück. Die Keys entsprechen den Control-Namen und die Values den Control-Values. |
splitObject | Damit kann eines JSON-String in Key-Value-Paare zerlegt werden. Diese Funktion wird von getControls intern verwendet, auch vom After-Control um untergeordnete Controls in die Control-Chain einzufügen. |
stringify | Ähnlich JSON.stringify, allerdings wird etwas kompakterer Code erzeugt. |
Warning: Die Grundfunktionen des Context sollten nicht überschrieben werden, weder durch User-Extends, noch durch Controls mit Variable- oder Set-Anweisung, da es sonst zu Fehlern kommen kann.