UI

Form

Das Formularobjekt erlaubt die Verknüpfung eines HTML-Formulars mit einem Dataset. Eingaben und Events eines Formulars können so genutzt werden, um die Daten in einem Dataset zu manipulieren. Ein Input wird über data-attach an einen Event gebunden. In diesem Beispiel wird das Dataset nach jedem change-Event geändert.

<input data-attach="change" ...>

Möchte man die Änderung über einen Button abschicken, so kann man nach dem Namen des Event einen Selector angeben. Jetzt wird der Eventhandler für das Feld an den click-Event des Buttons gebunden.

<input data-attach="click:#addbutton" ...>
<button id="addbutton">hinzufügen</button>

Als nächstes muss man den Wert der genommen werden soll deklarieren. In der einfachsten Form wird nur der Wert vom Control ausgelesen. Hierzu wird das Schlüsselwort value als data-handler definiert.

<input data-handler="value" ...>

Über die Methode transformValues() können verschiedene Funktionen zum Bearbeiten der Werte eingesetzt werden. Im folgenden Beispiel wird der Wert aus dem Input-Feld genommen und anschließend alle Zeichen in Kleinbuchstaben umgewandelt.

<input data-handler="value | strtolower" ...>

Über die beiden Attribute data-handler-before und data-handler-after können die Werte des Feldes gändert werden. Die Anweisungen im Attribute data-handler-before werden vor dem eigentlichen Handler ausgeführt und das Ergebnis der Transformation des Wertes wird in den Feldwert geschrieben. Nach der Entnahme des Feldwertes und Ausführung der Anweisungen aus data-handler werden die Anweisungen aus data-handler-after ausgeführt und das Ergebnis der Transformation in den Feldwert geschrieben.

data-handler-before > data-handler > data-handler-after

Das Data-Attribute data-registry definiert das Dataset in das der Wert eingetragen werden soll. So kann über

<input data-registry="myvalues | headline" ...>

ein Wert in der Map mit dem Schlüssel headline im Dataset myvalues gesetzt werden. Tiefergehende Verschachtelungen lassen sich über eine Pipe hinzufügen.

Hinweis

In diesem Attribute dürfen nur Indexe aus der Registry und keine Befehler aus der transformValue() verwendet werden.

Folgende Anweisung ist nicht möglich:

<input data-registry="myvalues | headline | strtolower" ...>

Handelt es sich bei dem Zieldaten nicht um eine Map oder soll ein anderer Befehl ausgeführt werden, so kann dieser über das data-action Attribute definiert werden.

<input data-action="append" ...>

Über das Data-Attribute data-prevent legt man schließlich fest ob der Event weitergegeben werden soll, oder die Verarbeitung abgebrochen werden soll. Dieses Attribute sorgt dafür, dass im Event preventDefault und stopPropagation
aufgerufen wird.

Im folgenden Beispiel haben wir eine Liste die über das folgende Dataset in die Registry eingetragen wurde.

dataset = new Alvine.DOM.Dataset({"headline": "Staedte", "list": ["Muenchen", "Frankfurt", "Berlin"]});
Alvine.Registry.set('myvalues', dataset);

Um die Liste leeren zu können, kann ein Button über folgendes HTML definiert werden:

<button data-attach="click" data-registry="myvalues | list" data-action="clear" 
        data-prevent="event">Liste leeren</button>

Der Event-Handler hängt am click-Event und verwendet die Dataset-Action clear auf die Collection list in dem Dataset myvalues.

dataset = new Alvine.DOM.Dataset({
               "headline": "Staedte", 
               "list": [
                      "Muenchen", 
                      "Frankfurt", 
                      "Berlin"]});
Alvine.Registry.set('myvalues', dataset);

Um nun einen Wert in diese Liste einzutragen erhält das Formular noch einen Eingabefeld und einen Button

<input data-attach="click:#addbutton" data-handler="value | htmlspecialchars" 
       data-registry="myvalues | list" 
       data-action="append" 
       data-prevent="event">

Um in einem Formular die Submit-Funktion zu deaktivieren, kann im form-Tag das Attribute data-prevent="submit" definiert werden.

<form data-prevent="submit">

Alternativ kann man auch einen Hidden-Tag nach folgendem Beispiel einfügen:

<input type="hidden" data-attach="submit:.auto-form" data-prevent="event">

Die Formulare können automatisch über die auto-form-Klasse initialisiert werden,

<form class="auto-form" ...>

oder alternativ manuell über Javascript. In diesem Fall muss dem Konstruktor entweder ein Selektor, eine HTML-Form-Element oder ein jQuery-Objekt übergeben werden.

// Selektor
form = new Alvine.UI.Form('#myform')
// jQuery-Objekt
form = new Alvine.UI.Form(jQuery('#myform'))
// HTML-Form-Element
form = new Alvine.UI.Form(jQuery('#myform').get(0))

Wird das Objekt nicht gefunden oder handelt es sich nicht um eine Form-Element, so wird eine Exception geworfen. Sind die data-Attribute bereits mit anderen Funktionen belegt, so kann über die Eigenschaft attributeprefix ein anderes Prefix gewählt werden.

form.attributeprefix='data-myprefix-';

Nach der Initialisierung des Form-Objektes muss das Objekt über die Form.attach() Methode an die DOM-Events gebunden werden.

// attachen der Events mit optionalem selector
form.attach(selector);

Der Optionale Selektor schränkt die Auswahl ein. Die attach() Methode verarbeitet im Standard alle Elemente die ein data-attach-Attribute besitzen.

Folgende Attribute sind verfügbar

Attribute Beschreibung Beispiel
attach Name des Events und optional ein Selector. Wird ein Selektor angegeben wird der Event dieses Objektes abonniert click[:#button]
handler Bereitstellung und Transformation des Wertes. Über das Pipesymbol können beliebige Befehle nacheinander ausgeführt werden. value | strtolower
handler-before Änderung des Wertes bevor dieser ausgelesen wird. Die Änderung dieses Handlers wird in den wert des Feldes geschrieben und ist für den Nutzer sichtbar. strtolower
handler-after Die Änderungen aus diesem Handler werden auf dem Wert des Kontrols (nicht auf den Wert des Handlers) ausgeführt und als Wert des Feldes gesetzt. strtolower
registry Definition des Pfades in der Registry. Angefangen mit dem Namen des Eintrags in der Registry, bis zum letzten Schlüssel cities | list
action Aktion die im Dataset ausgeführt werden soll. Für eine Map stehen die Aktionen: set, remove und clear zur Verfügung. Bei einem Dataset können append, remove und clear verwendet werden. set
prevent Verhindert das der Event weitergegeben wird. event

Leerzeichen, Pipes und Kommas sind Sonderzeichen und müssen, wenn Sie als Datum verwendet werden, mittels Backslash maskiert werden.

<input data-attributes="data-registry static:mytodos\ \|\ list\ \|\ {INDEX}\ \|\ issue"

erzeigt folgenedes Attribut

<input data-registry="mytodos | list | 1 | issue">

Der Platzhalter {INDEX} wird beim Wiederholen von Einträgen mit der laufenden Nummer des Eintrages, beginnend bei 0, ersetzt.

Möchte man den anderen Weg gehen und zum Beispiel einen Wert aus einer Liste löschen, so muss man einen Datensatz in der Registry über den data-handler spezifizierne und als Aktion remove definieren. Der Index=1 kann natürlich ebenfalls über {index} gesetzt werden.

<button data-attach="click" data-handler="registry:mytodos |  index:list | index:1" 
        data-action="remove">delete</button>

Vor und Nachbehandlung von Werten kann man über die Attribute data-handler-after und data-handler-before erreichen. Die Werte werden jeweils direkt in den Value des Elements geschrieben. In dem folgenden Beispiel werden zuerst alle Buchstaben umgewandelt ucwords und nach der Bearbeitung wird das Input-Feld mit dem Wert empty geleert

<input data-attach="click:#addbutton"
       data-handler-after="empty"
       data-handler-before="ucwords"
       data-handler="value | call:createObject" 
       data-registry="mytodos | list" data-action="append" data-prevent="event">

Änderungen in einem Dataset können auch im Formular angezeigt werden. Allerdings ist hierfür etwas Handarbeit notwendig. Im Dataset muss hierfür ein Observer registriert werden, der beim Aufruf den Wert im Formular zum Beispiel über jQuery(form).val() ändert.

Über die Methode Form.addHandlerParser(name, callback) können dem Formular Methoden zugewiesen werden. Diese Methoden können im Handler-Attribute verwendet werden.

form.addHandlerParser('doSomething', value => {
   ...
});
 <input data-handler="value | call:doSomething" ...>

Control

Das Control-Objekt dient zur definition weiterer UI-Elemente und definiert grundlegende Funktionen. Ein abgeleiteter Button könnte folgendes Template besitzen

<template id="button">
    <button type="button" data-attributes="
                id dataset:id, 
                class dataset:class,
                data-toggle dataset:tooltipText | ?:tooltip:,
                data-placement dataset:tooltipPosition,
                title dataset:tooltipText | i18n" 
                data-replace="dataset:content | call:convertHtmlFragment"></button>
</template>

Im Javascript sorgt folgender Code dafür, dass der Button erstellt wird.

function Button(content, options) {
    this.init('Button', 'mybutton', options);
    this.set('content', content);
}

Hier werden die Methoden des Controls "vererbt" und der Constructor richtig geetzt.

Button.prototype = new Alvine.UI.Control();
Button.prototype.constructor = Button;

Die Defaults werden, falls angegeben, durch Werte aus options ersetzt

Button.prototype.getDefaults = function () {
    return {
        "content": '&nbsp;',
        "id": "" + new Alvine.Types.ID(),
        "class": 'btn btn-primary',
        "tooltipPosition": undefined,
        "tooltipText": undefined
    };
};

Über getHtmlFragment wird aus dem Template ein HTMLFragment erstellt und dieses zurückgegeben.

Button.prototype.getHtmlFragment = function () {
    var template, dataset, fragment, jqMainControl;

    template = this.getTemplate('#button', 'Alvine.Package.UI.Dialog.Bootstrap');
    dataset = new Alvine.DOM.Dataset(this);

    fragment = template.getHtmlFragment(dataset);
    jqMainControl = jQuery(fragment).find('button');

    this.createReferenceID();
    return fragment;
};

Diese Methode wird nach dem einfügen des Buttons in das DOM aufgerufen und sorgt dafür, dass Funktionscode oder Eventhandler ausgeführt werden. In container wird das umliegende Element übergeben.

Button.prototype.activateControl = function (container) {
    this.assignReference(container);
    // Sonstiges
    container.find('button').tooltip();
};

Die Methode control.createReferenceID() erstellt eine eindeutige Referenz-ID für die Zuweisung eines DOM-Elements zum Control und legt diese ID auf den internen Referenz-Stack. Über Control.assignReference(container) wird dieser Stack abgearbeitet und das Control dem DOM-Element zugeordnet. Diese Methoden werden bei Bedarf von Control.activateControl(container) und Control.getHtmlFragment() aufgerufen. Die Methode Control.activateControl(container) gibt das verwendete jQuery-Objekt zurück.

Die Elemente im HTML-Template müssen das Attibute data-control-reference besitzen.

<div data-attributes="data-control-reference dataset:   "/>

Operationen

Das Control erweitert die Template.Operation um die Funktion convertHtmlFragment(obj). Diese Funktion überprüft die Eingabe auf den Type Alvine.UI.Control und Alvine.Types.Collection. Ist die Eingabe nicht von diesen Type, so wird es ohne Änderung ausgegeben.

Ist die Eingabe vom Typ Alvine.UI.Control, so wird das Ergebnis der Methode Alvine.UI.Control.getHtmlFragment() zurückgegeben. Ist das Objekt vom Typ Alvine.Types.Collection, so werden alle Elemente der Alvine.Types.Collection nacheinander durch die Funktion convertHtmlFragment(obj) bearbeitet und in einem DOM-Fragment zusammengefügt und zurück gegeben.

Fokus

Das Fokusobjekt Alvine.UI.Focus gibt einen DomPath für den aktuellen Fokus zurück. Das Objekt wird automatisch bei einer Änderung des Fokus im DOM gesetzt. Nach dem Setzen wird das Event dompathset gesendet.

Alvine.UI.Focus.getCurrentPath()

Über das Objekt lässt sich auch der Fokus über Alvine.UI.Focus.toCurrent(), Alvine.UI.Focus.toNext(), Alvine.UI.Focus.toPrevious() und Alvine.UI.Focus.to(element) ändern.