Offlinefähige und mobile Webanwendungen mit HTML5 und JavaScript-APIs

Seite 2: Model, View und ViewModel

Inhaltsverzeichnis

Um die Wartbarkeit und Testbarkeit zu steigern, trennt die hier betrachtete Anwendung HTML-Markup und JavaScript-Code unter Berücksichtigung des Model View ViewModel (MVVM), auch als Model View Presenter bekannt.

Das Muster MVVM teilt eine Anwendung in die drei Teile Model, View und ViewModel auf.

Dieses Muster sieht vor, dass die Anwendung in drei Teile geteilt wird. Model repräsentiert die Daten, zum Beispiel einen Pegelstand. Obwohl Model im Sinne der Objektorientierung Geschäftslogik innehaben könnte, die auf den Daten operiert, wird diese heutzutage häufig in eigene Klassen ausgelagert. Die View repräsentiert die GUI, mit der Benutzer interagieren. Als Bindeglied zwischen Model und View wird ein sogenanntes ViewModel eingesetzt. Es bereitet die Daten aus dem Model für die View auf und stellt darüber hinaus Präsentationslogik zur Verfügung.

Ein wichtiges Merkmal eines ViewModels ist, dass es die View nicht kennt. Der Brückenschlag zwischen den beiden Konzepten wird häufig über Datenbindung realisiert. Beispielsweise können Felder in der View an Eigenschaften des ViewModels gebunden werden. Selbiges gilt für Ereignisse, die in der View auftreten, wie Klicks auf Schaltflächen und Operationen im ViewModel. Idealerweise kümmert sich der Datenbindungsmechanismus sowohl um das Aktualisieren von GUI-Elementen in der View, wenn sich die damit verbundenen Eigenschaften im ViewModel ändern, als auch um das Übertragen von Benutzeränderungen von der View ins ViewModel.

Die freie Bibliothek knockout.js birgt die Möglichkeit, auf einfache Weise das Muster MVVM umzusetzen. Es sieht unter anderem das Konzept sogenannter Observables vor. Dabei handelt es sich um Objekte, die einen Wert speichern und Interessenten benachrichtigen, wenn sich der Wert ändert. So können die Eigenschaften von ViewModels die jeweiligen Views zur Aktualisierung auffordern.

Mit der von knockout.js bereitgestellten Funktion ko.observable kann der Entwickler Observables erzeugen. Ihr Wert lässt sich dann durch das Verwenden als parameterlose Funktion, zum Beispiel var x = myObservable(); , ermitteln. Soll er jedoch geändert werden, ist der neue Wert als Parameter zu übergeben (zum Beispiel myObservable(42);).

function PegelVM(pegel, isFav, onFavChanged) {
var $self = this;

$self.PegelId = ko.observable(pegel.PegelId);
$self.PegelName = ko.observable(pegel.PegelName);
$self.Gewaesser = ko.observable(pegel.Gewaesser);
$self.Wasserstand = ko.observable(pegel.Wasserstand);
$self.Datum = ko.observable(pegel.Datum);
$self.Meldestufe = ko.observable(pegel.Meldestufe);

$self.isFav = ko.observable(isFav);

$self.toggleFav = function () {
$self.isFav(!$self.isFav());

if (onFavChanged) onFavChanged($self);

}

$self.color = ko.computed(function () {
switch ($self.Meldestufe()) {
case 0: return "black";
case 1: return "orange";
case 2: return "red";
}
});

}

Der oben stehende Code zeigt ein Beispiel für eine Konstruktor-Funktion zum Erzeugen von ViewModels, die unter Verwendung von Observables Pegelstände repräsentieren. Wie bei solchen Funktionen üblich, weist sie die Eigenschaften des zu erstellenden Objekts der Variable this zu. Das Objekt wird an den Aufrufer zurückgegeben, sofern er die Funktion unter Verwendung des Schlüsselwortes new ausführt (zum Beispiel var vm = new PegelVM(...);).

Der Konstruktor erwartet drei Parameter: pegel repräsentiert einen vom Server via AJAX erhaltenen Pegelstand und somit das Model. Der Parameter isFav einthält einen booleschen Wert, der angibt, ob der jeweilige Pegelstand als Favorit angezeigt werden soll. onFavChanged verweist auf eine Callback-Funktion, die immer dann aufzurufen ist, wenn sich etwas am Favoriten-Status ändert. Da sich die Variable this in JavaScript an den aktuellen Kontext anpasst, kopiert die Konstruktor-Funktion ihren Wert in die Variable $self und verwendet fortan diese Variable an Stelle von this. PegelVM definiert die einzelnen Eigenschaften als Observables. Zum Erzeugen ruft sie die von knockout.js bereitgestellte Funktion ko.observable auf und übergibt dabei die Initialwerte als Parameter. Die stammen im Falle von PegelId, PegelName, Gewaesser, Wasserstand, Datum und Meldestufe aus dem übergebenen Pegel-Model.

Ob es sich beim vorliegenden Pegel um einen lokal zu speichernden Favoriten handelt, zeigt die Eigenschaft isFav. Daneben bietet die Funktion toggleFav die Möglichkeit, den Favoriten-Status umzukehren: Sie macht aus Favoriten Nicht-Favoriten und umgekehrt. Anschließend ruft sie die Callback-Funktion onFavChanged auf. Bei color handelt es sich um ein berechnetes Merkmal, dass die knockout.js-Funktion ko.computed nutzt. Diese nimmt eine weitere Funktion entgegen, welche im betrachteten Fall die Farbe des Pegelstandes in Abhängigkeit zur Meldestufe berechnet. Solche Eigenschaften stellen ebenfalls Observables dar – ändert sich die Grundlage für die Berechnung, erhalten Interessenten wie die View eine Benachrichtigung.