DOM¶
Funktionen und Objekte für die Manipulation des DOM.
Dataset¶
Das Dataset-Objekt ist eine Erweiterung des Map-Objektes und für die Verwendung mit dem Template-Objekt optimiert.
dataset = new Alvine.DOM.Dataset();
dataset.set('h1', 'My Headline');
Datasets lassen sich auch beliebig verschachteln und mit anderen Objekten füllen.
dataset = new Alvine.DOM.Dataset();
inner = new Alvine.DOM.Dataset();
dataset.set('index0', inner);
Datasets lassen sich auch durch einfache Objekte initialisieren. Dazu muss als Wert im Konstruktor
lediglich ein Objekt übergeben werden. Der Konstruktor erstellt aus diesem Objekt eine Datenstruktur aus
Alvine.Types.Map
für Objekte und Alvine.Types.Collection
für echte Arrays
obj = {
"headline": "Staedte",
"cities": [
"Muenchen",
"Frankfurt",
"Berlin"
]
};
dataset = new Alvine.DOM.Dataset(obj);
dataset.get('cities')
// ist vom Typ Alvine.Types.Collection
dataset.get('cities').toString
// -> Muenchen,Frankfurt, Berlin
Datasets können auch automatisch über einen Tageingebunden werden. Dazu muss ein HTML-Tag mit der Klasse auto-dataset in die HTML Seite eingefügt werden. Das Dataset kann entweder direkt per Attribute definiert werden data-dataset oder über Ajax nachgeladen werden data-dataurl. Das eingelesene Dataset wird in die Registry unter dem Namen der mit dem Attribute data-datakey angegeben wurde eingetragen.
<div class="auto-dataset" data-dataset="{'title':mydataset}" data-datakey="mykey"></div>
Das erstellte Dataset kann nun mit Javascript ausgelsen werden.
dataset = Alvine.Registry.get('mykey');
Wurde kein Key definiert, so wird ein Zufallswert für den Schlüssel genommen.
Wurde eine URL definiert und wird zusätzlich das Attribute data-bind angegeben, so werden Änderungen am Dataset per POST an diese URL übertragen.
<div class="auto-dataset" data-dataurl="http://example.com/mydata.json" data-bind="true"> </div>
Mit der Methode dataset.initMutationObserver()
wird ein MutationObserver initalisiert, der das DOM beobachtet und
bei Änderungen am DOM die Observer im Dataset rekursive bereinigt.
Objektreferenz¶
Dataset(initValues)
Beschreibung
Neues Objekt erstellen
Parameter-Liste
initValues (Alvine.Types.Map | Object | Array)
Werte mit denen das Dataset initialisiert wird. Aus Objekten werden Maps und aus Arrays Collection erstellt.
Rückgabewert
Gibt ein neues
Object
vom TypDataset
zurück.
Dataset.initMutationObserver()
Beschreibung
Beobachten von Änderungen am DOM und entfernen von Observern, die durch ein
bind
erstellt wurden.
Rückgabewert
Gibt die eigene Instanz zurück.
Dataset.toJSON()
Beschreibung
Diese Methode sollte nicht direkt aufgerufen werden. Diese Methode wird von
JSON.stringify()
aufgerufen. Siehe hierzu auch die Beschreibung bei developer.mozilla.org
Rückgabewert
Daten des Dataset in der von JSON.stringify geforderten Form.
Dataset.toString()
Beschreibung
Erstellt aus den Daten eine Zeichenkette
Rückgabewert
Daten des Dataset als Zeichenkette (
String
)
Template¶
Das Templateobjekt erlaubt es mit dem neuen HTML5 Template-Tag zu arbeiten. Wie in dem folgenden Beispiel zu sehen ist der neue Template-Tag eine gute Möglichkeit HTML-Templates direkt im HTML zu definieren. Der Vorteil der Templates ist, das diese zur Ladezeit nicht gerendert werden und somit keinen nenswerten Speicher und Rechenleitung verbrauchen.
<template id="mytemplate" class="templates">
<div>
<h1>Template 2</h1>
<p>Platzhalter</p>
</div>
</template>
Auf dieses Template kann nun einfach über das Template-Objekt zugegriffen werden.
template = new Alvine.DOM.Template('#mytemplate');
Werden keine Templates mit dem Namen gefunden so wird eine Exception geworfen. Werden mehrere Templates gefunden, so wird mit get(0) das erste aus der Liste der gefundenen genommen. Um das Template in eine andere Struktur einfügen zu können, kann man mit der Methode Template.getjQueryObject() ein jQuery-Objekt erstellen und dieses per jQuery.append() einfügen.
Neben einem Selector kann ein Template auch direkt aus einem jQuery-Objekt erstellt werden
template = new Alvine.DOM.Template(jQuery('#mytemplate'));
Alternativ kann man sich per Template.getHtmlFragment() ein echtes DOM-Objekt holen.
obj = template.getjQueryObject();
// -> jQuery-Objekt
jQuery('<div/>').append(obj);
template.getHtmlFragment()
// -> Document-Fragment Objekt
Den Methoden Template.getjQueryObject() und Template.getHtmlFragment() kann ein Dataset übergeben werden. Das Dataset dient dazu Werte innerhalb des Templates zu ersetzen.
_Der Schlüssel ___INDEX ist ein geschützter Wert, der intern für den Index benutzt wird. Datasets dürfen keinen Wert mit diesen Schlüssel enthalten.
Hinweis
Um Änderungen an Datasets im DOM abzubilden wird im Dataset ein Observer eingehängt. Wird das per bind
gebundene
Element aus dem DOM gelöscht, so bekommt das dataset das nicht mit und der Observer im dataset bleibt zurück. Damit
dies nicht passiert, muss das dataset über einen MutationObserver verfügen: dataset.initMutationObserver()
Zum Thema MutationObserver siehe auch folgende Quellen
- https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
- https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord
Sequenzdiagramm¶
Objektreferenz¶
Template(selector)
Beschreibung
Die Methode sucht über den Selektor im aktuellen Dokument das entsprechende Template. Werden mehrere Templates gefunden, so wird nur das erste Template genommen.
Parameter-Liste
selector (String | jQuery)
jQuery-Selektor wie in der jQuery-Dokumentation beschrieben.
Rückgabewert
Neues Objekt vom Typ
Template
Template.getjQueryObject(map)
Beschreibung
Diese Methode ruft
Template.getHtmlFragment(map, false)
auf.
Parameter-Liste
map (Alvine.Types.Map)
Daten, die für das Erstellen des HTML-Fragments verwendet werden sollen.
Rückgabewert
Gibt ein
HTMLFragment
zurück
Template.getHtmlFragment(dataset, elementFlag)
Beschreibung
Liefert das Template zurück.
Parameter-Liste
dataset (Alvine.Types.Map | Alvine.DOM.Dataset)
Die zum Erstellen des HTML-Fragments zu verwendende Daten. Wird kein Dataset übergeben, so wird das im Template hinterlegte Dataset genutzt.
elementFlag (Boolean)
Bei true wird eine DOM-Node und bei false ein jQuery-Objekt zurückgegebe
Rückgabewert
Gibt ein
HTMLFragment
als DOMNode oder jQuery zurück.
Template.toString()
Beschreibung
Die Methode erstellt ein HTML-Fragment und wandelt diese in eine Zeichenkette um.
Rückgabewert
Gibt eine Zeichenkette mit dem entsprechenden HTML zurück.
Wichtig
Hierbei gehen alle Bindungen der Nodes verloren
Inhaltsmanipulation¶
In Anlehnung an die PHP-Erweiterung Alvie.Markup.HTML können auch im Javascript data- Attribute zum Einsatz kommen.
<template id="template">
<div>
<h1 data-replace="dataset:h1">Template</h1>
</div>
</template>
Um das Template mit Werten zu füllen, muss ein Dataset erstellt und mit Werten erfüllt werden
dataset new Alvine.DOM.Dataset();
dataset.set('h1', 'My Headline');
mytemplate = template.getjQueryObject(dataset);
Das Ergebnis-HTML in mytemplate hat dann folgenden Inhalt
<div>
<h1>My Headline</h1>
</div>
Neben der einfachen Ersetzung können auch noch weitere Befehle durch Pipes getrennt im Attribute übergeben werden. Die einzelnen Befehle bearbeiten immer die Ausgabe des vorherigen Befehls.
<template id="template">
<div>
<h1 data-replace="dataset:h1 | strtolower">Template</h1>
</div>
</template>
Das Ergebnis des folgenden Templates ist dann eine komplett kleingeschriebene Überschrift.
<div>
<h1>my headline</h1>
</div>
Das Template-Objekt verwendet für die Transformation der Werte die Methode transformValues.
Über die Operation Eigenschaft des Template-Objektes lassen sich weitere Funktionen einfügen. Somit lassen sich alle Manipulationen des Wertes bewerkstelligen. Die eigene Operation wird über das call Schlüsselwort aufgerufen. Alle Werte die nach dem Namen der Funktion per Doppelpunkt angegeben werden, werden direkt an die Funktion übergeben.
<p data-replace="dataset:key | call:getFullname:!">Text</p>
// Template-Objekt erstellen
template = new Alvine.DOM.Template(selector);
// Operation definieren
template.Operation.getFullname = function(value, sign) {
return value+sign;
};
// Der Operator muss vor dem Aufruf der Funktion getHtmlFragment() definiert sein.
template.getHtmlFragment(dataset);
Ein weiterer Befehl ist data-replaceself. Hier wird nicht der Wert des Elements gesetzt, sondern das gesamte Element ersetzt.
<template id="template">
<div>
<h1 data-replaceself="dataset:h1 | strtolower">Template</h1>
</div>
</template>
Führt also zu folgendem Ergebnis ohne H1 Tags
<div>
my headline
</div>
Attribute lassen sich ebenso einfach über ein Dataset setzen. Dazu muss im Tag nur der Befehl data-attributes gesetzt werden.
<template id="template7" class="templates">
<div>
<a data-attributes="href dataset:url | strtolower, style static:color:red, class dataset:class | strtoupper">Link</a>
</div>
</template>
Möchte man als Wert des Attributes das Attribut eines anderen Objektes auslesen und verwenden, so bietet sich jQuery an.
Kombiniert mit einem Präfix oder Suffix können so schnell und einfach ID gesetzt werden. Der erste Parameter nach jQuery
ist der Selektor, gefolgt von der jquery-Funktion attr
und dem Namen des gewünschten Attributes. Um den Wert eines
anderen Elements auszulesen, muss `val
und für Eigenschaften prop
verwendet werden (entsprechend der jQuery Dokumentation).
<input data-attributes="id jquery:#todolisttemplate:attr:id | suffix:-{INDEX}">
Template-Tags eignen sich optimal für die Bereitstellung der benötigten HTML-Struktur. Allerding benötigt man manchmal ein Template aus einer bestehenden Struktur. Auch damit kann das Template-Objekt umgehen.
<div id="domtemplate" data-attributes="id static:newid">
<p><i data-replace="static:testvalue"></i></p>
</div>
Beim Erstellen des Template-Objektes den gewünschten Selektor angeben. Der umschließende Tag wird in diesem Fall allerdings im Template verwendet und nicht wie bei den Template-Tags entfernt. Deshalb ist es wichtig, falls das Element wie im obigen Beispiel eine ID besitzt, eine neue ID mittels Attribute-Ersetzung zu setzen.
template = new Alvine.DOM.Template('#domtemplate');
Eine weitere Funktionalität des Template-Objektes ist das Wiederholen von Werten aus einer Collection. Dadurch lassen sich Datasets einfach in HTML-Abbilden. Im folgenden Beispiel soll eine Tabelle mit Städten ausgegeben werden. Dazu wird ein HTML-Template mit einer Tabelle und mit der zu wiederholenden Zeile angelegt.
<template id="template" class="templates">
<div>
<table>
<tr data-repeat="city dataset:list">
<td data-replace="dataset:city">placeholder</td>
</tr>
</table>
</div>
</template>
Im nächsten Schritt muss das Dataset definiert werden.
template = new Alvine.DOM.Template('#template9');
// Collection mit Städten
list = new Alvine.Types.Collection();
list.append('München');
list.append('Frankfurt');
list.append('Berlin');
// Collection dem Dataset hinzufügen
dataset = new Alvine.DOM.Dataset();
dataset.set('list', list);
// Diese Anweisung erstellt das fertige HTML
template.getHtmlFragment(dataset);
Das Ergebnis dieses Javascripts ist folgender HTML Schnipsel.
<table>
<tbody>
<tr>
<td>München</td>
</tr>
<tr>
<td>Frankfurt</td>
</tr>
<tr>
<td>Berlin</td>
</tr>
</tbody>
</table>
Neben dem Zugrif auf das Dataset, kann man auch auf Datesets in der Registry
zugreifen. Hierzu muss nur das Schlüsselwort registry
in dem Auswahlattribute
geschrieben werden.
<tr data-repeat="city registry:key">
Das Dataset kann neben der Zuweisung durch die Programmierung auch über HTML-Attribute zugewiesen werden. Dazu kann das Dataset entweder direkt im Tag angegeben werden oder es wird eine URL definiert über die das Dataset nachgeladen wird.
<!-- Beispiel mit Dataset im Attribute -->
<template id="template" class="templates" data-dataset='{"headline": "Staedte","list": ["Muenchen","Frankfurt","Berlin"]}'>
<div>
<table>
<tr data-repeat="city dataset:list">
<td data-replace="dataset:city">placeholder</td>
</tr>
</table>
</div>
</template>
Wichtig beim Nachladen des Datasets ist es, dass als Ergebnis ein JSON-Objekt zurückgegeben wird.
<!-- Beispiel mit URL -->
<template id="template" class="templates" data-dataurl='http://www.example.com/dataset.json'>
<div>
<table>
<tr data-repeat="city dataset:list">
<td data-replace="dataset:city">placeholder</td>
</tr>
</table>
</div>
</template>
Beim Nachladen der Daten von einer URI gibt es eine Besonderheit zu beachten. Da Ajax-Requests asynchrone ablaufen steht das Dataset nicht sofort zur Verfügung. Vielmehr muss vor der Aufführung der Template.getHtmlFragmen() Funktion im Code auf das loaddataset.DONE Event geprüft werden.
jQuery(window).on('loaddataset.DONE', function(m, p) {
try {
template.getHtmlFragment();
} catch(e) {
// ..
}
});
Der Fehlerfall wird über das Event loaddataset.FAIL gemeldet.
Ganz ohne Javascriptprogrammierung kann man ein Template über die auto-template Klasse initialisieren. Dazu muss man neben der auto-template Klasse, dem Dataset (als URL oder Json), auch noch ein Target definieren.
<template class="auto-template" data-target="#mytarget" data-dataset=...
Das Target-Attribute muss ein jQuery-Selector sein und dient als Ziel für das erstellte HTML-Fragment. Das HTML-Fragment wird per jQuery(target).append(template) in das Dokument eingefügt.
<div id="mytarget"></div>
Die Funktionsweise ist dann identisch zu den oben beschrieben Funktionen.
Element aus Template erstellen¶
in der anderen Richtung funktioniert die Zuweisung über die Klasse auto-render. Ein Element das diese Klasse besitzt braucht zusätzlich die Attribute data-template und data-dataset oder data-dataurl.
Die Funktionsweise und Konfiguration ist identisch. Als Template wird das erste, über den im data-template Attribute definierten Selektor, gefundene Element genommen.
<div>
DOM-Elemente an Dataset binden¶
Möchte man einzelne Werte oder eine ganze Collection auf Änderungen überwachen, so kann man das per data-bind-Attribute im Template definieren. Im folgende Beispiel wird ein Template mit einer Überschrift und einer Tabelle mit einer Spalte definiert.
<div id="targetForTemplate"></div>
<template id="listTemplate">
<div>
<h2 data-replace="dataset:headline" data-bind="true" data-bind-tags="my headline">dummy</h2>>dummy</h2>
<table>
<tr data-repeat="city dataset:list" data-bind="true">
<td data-replace="dataset:city">placeholder</td>
</tr>
</table>
</div>
</template>
Um das Template mit Daten zu füllen, wird ein Dataset aus einer Liste mit den drei Städten München, Frankfurt und Berlin, erstellt.
dataset = new Alvine.DOM.Dataset({"headline": "Staedte", "list": ["München", "Frankfurt", "Berlin"]});
template = new Alvine.DOM.Template('#listTemplate');
// Zuweisen des Templates in einen Div-Container
jQuery('#targetForTemplate').append(template.getHtmlFragment(dataset));
Nach dem Laden der Seite wird eine Tabelle angezeigt. Ändert man nun Werte im Dataset, so ändert sich auch die Darstellung in der Webseite.
// Überschrift neu setzen
dataset.set('headline', 'Meine Städte');
// Einen Wert zur Liste hinzufügen
dataset.get('list').append('Bern');
// Berlin entfernen
dataset.get('list').remove('Berlin');
Der Observer des Bindings kann mit Tags ausgezeichnet werden. Hierzu kann man das Attribute data-bind-tags
verwenden.
<h2 data-replace="dataset:headline" data-bind="true" data-bind-tags="my headline">dummy</h2>
Der Observer enthält jetzt die beiden Tags my und headline die zum Beispiel für Abfragen oder das debuggen hilfreich sind.
AutoInit¶
Die Methode `AutoInit.run()
wird von der Renderfunktion des Templates aufgerufen und hilft dabei
Eventhandler und Initialisierungen nach einer neuen Darstellung von Inhalten zu initialisieren. Das
Objekt Alvine.DOM.AutoInit hat eine Collection als Prototyp und besitzt somit alle Methoden einer Collection.
Eine neue Initialisierungsfunktion wir folgendermaßen integriert:
Alvine.DOM.AutoInit.append(function() {
// .....
})
Werden über das AutoInit DOM-Elemente initialisiert, so muss jede Initialisierungsfunktion selber dafür sorgen das es zu keiner doppelten Initialisierung kommt.