Forms over Data mit Knockout.js

Текст
Автор:
0
Отзывы
Читать фрагмент
Отметить прочитанной
Как читать книгу после покупки
Forms over Data mit Knockout.js
Шрифт:Меньше АаБольше Аа

Aus der Praxis: Forms over Data mit Knockout.js
Warum dieses Buch entstanden ist

JavaScript ist böse. Denn JavaScript hat keine feste Typisierung und ganz merkwürdige Sprachkonstrukte. Zitate wie „Manchmal muss man mit new arbeiten, manchmal nicht und keine Sau weiß warum“ (http://www.peterkropff.de/site/javascript/besonderheiten.htm) belegen, dass diese Probleme nicht nur vom Autor dieses Buches so empfunden werden. Hinzu kommt, dass Vererbung mit JavaScript ein Feld des Leidens ist und Namensräume nur über ganz seltsame Funktionsdefinitionen Einzug halten. Alle diese Eigenschaften legen nahe, sich nie mit JavaScript zu beschäftigen. Wir wollen produktiv sein und nicht Esoterik betreiben.

Auf der anderen Seite ist JavaScript aber die Assembly Language des Web (http://kouder.net/2011/07/12/javascript-das-assembler-von-morgen/).

Jeder Browser versteht sie und kann sie ausführen. Sie ist die einzige Möglichkeit, Code auf allen Zielrechnern ohne Plug-in auszuführen und damit für clientseitig aktive Seiten zu sorgen. JavaScript ist mit HTML5 unmittelbar verbunden und jeder, der künftig diese Technologie verwenden will oder muss, muss sich mit JavaScript auseinandersetzen.

Wer das aber tut, hat mit den vielen Nachteilen zu kämpfen, die schon aufgezählt wurden, was uns wieder an den Anfang dieser Einleitung bringt.

Um das Erlernen von JavaScript kommt man also nicht herum. Allerdings kann man sich viel Funktionalität über Bibliotheken holen, die es frei im Internet gibt. So wie Knockout.js.

Über diese Bibliothek stolperte ich durch Zufall. Das Pattern Model-View-ViewModel – und vor allem seine Vorteile – war mir durch die Windows Presentation Foundation (WPF) von Microsofts .NET hinlänglich bekannt. Was lag also näher, als gleich Nägel mit Köpfen zu machen und JavaScript in einem aktuellen Umfeld zu lernen. Mit Knockout.js als Verbindung zwischen Daten und Darstellung.

Ich zahlte eine Menge Lehrgeld, denn die erste Zeit war ein permanentes Auf und Ab der Gefühle. Erste Schritte klappten, dann etwas verändert und schon ging nichts mehr (siehe auch http://radar.oreilly.com/2011/06/time-to-learn-javascript.html).

Um das durch hartes Ausprobieren Gelernte nicht wieder zu vergessen, schrieb ich meine Erfahrungen auf – daraus ist dieses Buch entstanden, das Sie gerade lesen.

Es soll Ihnen helfen, bei den typischen Aufgaben in einem Forms-over-Data-Projekt nicht immer wieder so zu stocken, wie das bei mir der Fall war.

Tilman Börner

PS: Versöhnlich muss ich inzwischen zugeben: JavaScript ist immer noch merkwürdig, aber die Möglichkeiten sind beachtlich und das Feilen, wie etwas funktionieren könnte, macht auch Spaß.

Knockout.js: Das MVVM-Framework

Sie ist klein, aber unglaublich mächtig. Sie ist gewöhnungsbedürftig, aber irgendwie auch genial. Knockout.js ist in jedem Fall eine JavaScript-Bibliothek, die dabei hilft, Daten, Logik und Darstellung sauber voneinander zu trennen.

Und Trennung ist wichtig. Unzählige Projekte scheitern irgendwann und müssen neu geschrieben werden, weil der Code ein in sich verwobenes Knäuel an Methodenaufrufen ist. Da hilft auch die Objektorientierung nicht automatisch weiter. Erst wer sich an größere Design Pattern wie Model-View-Controller oder Model-View-ViewModel hält, schafft die Trennung. Der geringe Mehraufwand bringt im Endeffekt aber viele Vorteile mit sich: Logik und Datenverarbeitung sind testbar, da sie auch ohne Oberfläche ansprechbar sind, und es lässt sich auf die Logik recht einfach eine andere Oberfläche setzen, wenn beispielsweise plötzlich eine mobile Variante einer Website gefordert wird.

Außerdem können mehrere Entwickler gleichzeitig an verschiedenen Einheiten entwickeln, ohne sich ins Gehege zu kommen.

Knockout.js ist ein Framework, dessen Ziel es ist, für genau diese Trennung zu sorgen. Es handelt sich um ein Model-View-ViewModel-Framework. In der Bezeichnung stecken die drei Komponenten, aus denen es besteht:

View

Die View legt fest, wo welches Control einer Seite platziert sein soll und welches Aussehen es hat. Im Zusammenhang mit Knockout ist das eine Webseite, die per HTML und CSS beschrieben wird.

Model

Das Model ist der Teil im Programm, der sich um die Daten kümmert, die angezeigt werden sollen. Es liest beispielsweise Datensätze aus einer Datenbank, schreibt sie zurück und so weiter.

ViewModel

Das ViewModel ist das Modul, das auf Eingabeaufforderungen aus der View reagiert und Daten an die View zurückschickt. Es stellt sozusagen die Weichen für die Daten, die aus der Datenbank kommen, und sorgt dafür, dass sie im richtigen Gleis – also dem richtigen Control – einlaufen.


Abbildung 1: So fließen die Daten in einer Single-Page-Anwendung.

Knockout.js vollzieht diese Trennung – wie der Name schon vermuten lässt – für die Sprache JavaScript.

Die Dokumentation von Knockout.js auf der Website http://Knockoutjs.com ist schon recht gut. Trotzdem stolpert man über das ein oder andere Problem, das nicht von der Dokumentation behandelt wird.

Knockout.js ist selbst eine JavaScript-Bibliothek und wird ganz einfach über eine Zeile wie

<script src="knockout-2-0-0.js"></script>

in eine HTML-Seite eingebunden. Dann sorgt Knockout.js im Hintergrund dafür, dass Events verarbeitet und Daten zurückgegeben werden.

Ein erstes kleines Beispiel soll das illustrieren.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head>

<title></title>

<script src="knockout-2.0.0.js"

type="text/javascript">

</script>

</head>

<body>

<div data-bind="text: lastname">

</div>

<script type="text/javascript">

var viewModel =

{

"lastname": ko.observable("Gertrud")

}

ko.applyBindings(viewModel);

</script>

</body>

</html>

knockout-2.0.0.0.js muss natürlich im selben Verzeichnis liegen wie die HTML-Datei. Wenn nicht, muss der Pfad zu ihr angepasst werden.

Was passiert in dieser Webseite? Die HTML-Datei ist eine View. Alles, was nicht innerhalb der script-Tags steht, gehört dazu. In diesem Beispiel ist die Logik, sprich das JavaScript, in die View eingebettet. Bei größeren Views empfiehlt sich natürlich, den Code in einer eigenen js-Datei auszugliedern.

Neben html, head, title und body gehört dazu insbesondere die Zeile mit dem div-Tag. Diese Zeile definiert ein einfaches Label-Control, also die Anzeige eines Strings.

Die Teile der Datei, die in die script-Tags eingebettet sind, enthalten einmal die Referenz zur Knockout-Bibliothek und dann noch Code, der die Logik des Beispiels ausmacht.

Im Gegensatz zu anderen Bibliotheken bedarf es immer eines ViewModels – im Beispiel durch die Variable viewModel festgelegt.

Im ViewModel wird eine Observable (Funktion) mit Namen lastname über ko.observable() definiert. ko.observable("Gertrud") legt den Anfangswert auf Gertrud fest. ko.observable() ist eine Funktion von Knockout.js, die dafür sorgt, dass Änderungen an dem Feld an die View übermittelt werden und umgekehrt.

Um den Knockout.js-Mechanismus in Gang zu setzen, damit also aus dem div-Tag eine Art Label wird, bedarf es noch eines Aufrufs von

ko.applyBindings(viewModel);

Die Zeile verbindet ko.observable() im ViewModel mit den Kontrollelementen in der View. Welche Daten wohin müssen, wird in der View durch das Attribut data-bind festgelegt. Sie sehen das im div-Tag:

data-bind="text: lastname"

Das Attribut koppelt die Eigenschaft text des div-Elements an das Datenfeld lastname im ViewModel viewModel.

Wenn Sie die Seite aufrufen, sehen Sie das überwältigende Ergebnis dieser paar Zeilen: Gertrud erscheint auf dem Bildschirm.

Nun hört sich Gertrud nicht unbedingt nach Nachname an, weshalb sich die Frage stellt, ob man das nicht korrigieren kann. Der Sinn von Knockout.js wäre verfehlt, würde das nicht gehen. Mit dem Aufruf

viewModel.lastname("Huber");

setzen wir lastname auf Huber. Ein Reload der HTML-Seite zeigt, dass jetzt das Ergebnis stimmt. Auf dem Bildschirm erscheint Huber.

Das ganze Beispiel sieht damit folgendermaßen aus:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

<head>

<title></title>

<script src="knockout-2.0.0.js"

type="text/javascript">

</script>

 

</head>

<body>

<div data-bind="text: lastname">

</div>

<script type="text/javascript">

var viewModel =

{

"lastname": ko.observable("Gertrud")

}

ko.applyBindings(viewModel);

viewModel.lastname("Huber");

</script>

</body>

</html>

Die letzte Zeile zeigt, wie Sie Einfluss auf die Daten in der View erhalten: Sie setzen den Wert durch einen Aufruf der Funktion mit dem neuen Wert als Parameter, und wie durch Zauberhand spiegelt sich das in der View wider.

Unter .NET muss man diesen Aufruf durch den INotifyPropertyChanged-Mechanismus selbst implementieren. Dann wird im Setter der Eigenschaft ein Event ausgelöst, was dem MVVM-Framework mitteilt, dass sich etwas verändert hat. Unter JavaScript gibt es keine Setter, und damit muss das Setzen des Wertes eben über die Methode erfolgen.

Auch das Lesen des Wertes erfolgt über die Funktion. Setzen Sie noch die folgende Zeile an das Ende des Skripts:

console.log(viewModel.lastname());

Jetzt wird im console-Bereich der Name ausgegeben: Huber.

Das value-Binding

Bei einem div-Element, das vom Anwender keine Daten entgegennehmen kann, ist das natürlich etwas langweilig. Wenn Sie aber aus dem div-Element ein input-Element machen, wird das Ganze schon interessanter.

<input data-bind="value: lastname" />


Abbildung 2: Das erste kleine Programm. Der in die Textbox eingegebene Wert ist im ViewModel sichtbar. Siehe dazu Tipp 1 und Tipp 2.

Wie Sie sehen, müssen Sie allerdings auch das Binding anpassen. Statt text ist es hier nun die Eigenschaft value. Ansonsten funktioniert alles ganz genauso.

Tipp 1: Die Konsole

Unter dem Browser Google Chrome und unter dem Internet Explorer gibt es eine Konsole, die Fehlermeldungen anzeigt, aber auch für die Ausgabe von Debug-Informationen genutzt werden kann. Unter Chrome schalten Sie die Konsole mit [Strg]+[Shift]+[I] ein, beim Internet Explorer führt [F12] zum Ziel. Über console.log(text) lässt sich darüber auch der Text text ausgeben.

Tipp 2: Die Debug-Sektion

In vielen Fällen ist es für das Debuggen hilfreich, einen Blick in das ViewModel zu werfen. Statt das immer über console.log-Aufrufe oder gar über alert-Anweisungen zu tun, können Sie Knockout.js auch dafür verwenden. Fügen Sie dazu im unteren Bereich der HTML-Seite noch folgende Anweisungen hinzu:

<hr />

<h2>Debug</h2>

<div data-bind="text: ko.toJSON(viewModel)">

</div>

Die letzte Zeile zeigt den Dateninhalt des ViewModels an.

Купите 3 книги одновременно и выберите четвёртую в подарок!

Чтобы воспользоваться акцией, добавьте нужные книги в корзину. Сделать это можно на странице каждой книги, либо в общем списке:

  1. Нажмите на многоточие
    рядом с книгой
  2. Выберите пункт
    «Добавить в корзину»