Part 2 – knockoutJS

6. August 2013

Im letzten Artikel haben wir eine kleine, schnelle und möglicherweise auch nicht ganz vollständige Geschichte über JavaScript und die ersten aufkommenden Frameworks gehört 🙂 In den kommenden Beiträgen geht es darum, die im letzten Vortrag genannten Frameworks knockoutJS und AngularJS ein wenig zu beleuchten und aufzuzeigen, welche Vorteile diese Frameworks bieten. Beginnen möchte ich in dem heutigen Beitrag mit dem Framework, welches einen wortwörtlich “umhaut” 😉

 

KnockoutJS

knockoutJS  ist ein ziemlich kleines JavaScript Framework mit einer Größe von 40kb und bietet im Wesentlichen vier Kernfunktionalitäten:

  • Declarative Bindings
  • Automatic UI Refresh
  • Dependency Tracking
  • Templating

Das bedeutet im Wesentlichen, dass dem Einsatz des Model-View-ViewModel Patterns und Two-Way-Data Binding nichts mehr im Wege steht.

Das Wichtigste, was uns knockoutJS bietet, sind Observables. Observables sind quasi der Kleber zwischen unseren JavaScript-Objekten (ViewModels) und den HTML-Elementen (View). Über eine definierte Syntax werden die Eigenschaften des ViewModels an die HTML-Elemente gebunden (Data Binding).

Gibt es Änderungen in einer Eigenschaft des ViewModels, werden diese sofort im View aktualisiert. Umgekehrt funktioniert das genauso. Ändert sich ein Eintrag z.B. in einem Textfeld, wird das direkt in die Eigenschaft des ViewModels geschrieben. Früher mussten händisch Eventhandler erstellt werden, um diesen Mechanismus abzubilden. Heute übernehmen diese Arbeit Frameworks wie knockoutJS für uns.

Am besten machen wir jetzt ein kleines Beispiel und bringen auch endlich ein wenig Code ins Spiel. Wie heutzutage üblich, machen wir uns ein kleines “Hello World”-Programm in Form einer kleinen Todo-Liste, um die Konzepte hinter knockoutJS besser zu verstehen.

Praxis

Unsere Todo-App soll eine Liste enthalten und dort sämtliche erfassten Todos darstellen. Es gibt ein Textfeld und einen Button zum Hinzufügen neuer Todo-Einträge. Die einzelnen Todos können über eine Checkbox auf “Fertig” und “Noch zu erledigen” gesetzt werden.

Schauen wir uns zunächst das ViewModel an:

   1: function TodoListVM(){

   2:     var self = this;

   3:     self.todos = ko.observableArray([

   4:         {

   5:             description: "Müll raus bringen",

   6:             done: ko.observable( false )

   7:         },{

   8:             description: "Kinokarten bestellen",

   9:             done: ko.observable( false )

  10:         }

  11:     ]);

  12:     self.newTodo = ko.observable();

  13:     self.add = function(){

  14:         self.todos.push({

  15:             description: self.newTodo(),

  16:             done: ko.observable( false )

  17:         });

  18:     }

  19: }

  20: ko.applyBindings(new TodoListVM());

Hier haben wir unser ViewModel für die Todo-Liste. Es gibt ein Feld todos zum Halten der Todo-Einträge. Initial fügen wir zwei Einträge hinzu. Des Weiteren gibt es ein Feld newTodo, welches den Beschreibungstext für einen neuen Todo-Eintrag enthält. Als Letztes haben wir noch eine Funktion, die aufgerufen wird, um Todo-Einträge hinzuzufügen.

Der Aufruf ko.applyBindings(..) am Ende sorgt dafür, dass unser ViewModel an das DOM der Seite gebunden wird. Dieser Aufruf gießt quasi den Kleber zwischen den HTML-Elementen und unserem ViewModel in die Seite.

Die Eigenschaft todos unseres ViewModels ist ein observableArray(..). Durch diese Zuweisung wird sichergestellt, dass beim Hinzufügen eines weiteren Todo-Eintrags automatisch das View aktualisiert wird.

Als Nächstes haben wir mit der Eigenschaft newTodo noch ein “einfaches” observable. Diese Eigenschaft wird gefüllt, sobald wir in dem gebundenen Textfeld einen Text eingeben. Ausgelesen wird newTodo, wenn die Funktion add() aufgerufen wird. Das passiert sobald wir auf den Add-Button drücken.

Nachdem unser ViewModel steht, kommen wir nun zur HTML-View und dem Data Binding:

   1: <div data-bind="foreach: todos">

   2:     <div>

   3:         <input type="checkbox" data-bind="checked: done" />

   4:         <span data-bind="text: description, css: {todoDone: done}"></span>

   5:     </div>

   6: </div>

   7: <input type="text" data-bind="value: newTodo" />

   8: <button data-bind="click: add">Add</button>

Hier sehen wir unsere HTML-View. Auf den ersten Blick sehen wir hier divs, spans und input Felder. Ganz normale HTML-Tags. Des Weiteren sehen wir aber auch knockoutJS spezifische Attribute wie z.B. data-bind. Diese Attribute werden benutzt, um das Binding zwischen den Eigenschaften des ViewModels auf die entsprechenden HTML-Element herzustellen.

Sieht man genauer hin, hat man in dem data-bind Attribut die Möglichkeit, Ausdrücke zu erzeugen. Diese Ausdrücke erklären dem Binding, was gemacht werden soll.

Beispiel: <input type=”text” data-bind=”value: newTodo” />

Hier wird folgendes beschrieben: Nimm aus dem ViewModel die Eigenschaft newTodo und binde diese an das input-Element an dessen value-Attribut.

Auch interessant ist das Binding für die todos. Hier sagen wir dem Binding, dass es bitte mit jedem Todo-Item aus der todos-Eigenschaft des ViewModels etwas Bestimmtes anstellen soll. Das, was er tun soll, wird einfach zwischen das HTML-Element geschrieben und ist im Grunde nichts anderes als ein Template, welches zum Rendern jedes Todo-Eintrags genutzt wird.

Das Data Binding funktioniert sowohl für Daten zum Eingeben als auch für Style-Attribute, CSS-Klassen und alles was es sonst noch an Attributen gibt. Das Limit ist an dieser Stelle, wie fast überall, die Fantasie 😉

Nun ist es Zeit, die Früchte unserer Arbeit zu betrachten:

knockoutScreen

Hier sehen wir das Ergebnis. Ich habe hier schon einen neuen Todo-Eintrag erstellt und mit Add der Liste hinzugefügt. Zudem wurde “Müll raus bringen” als “erledigt” markiert.

Fazit und Ausblick

An dieser Stelle möchte ich nochmal darauf hinweisen, dass für jede Aktualisierung der View oder auch des ViewModels keinerlei Eventhandler geschrieben wurde. Die Zuweisung von Werten aus der View zum ViewModel oder die Aktualisierung der UI musste nicht manuell über Eventhandler realisiert werden! Diesen “Schmerz” nimmt einem knockoutJS ab, sodass man sich auf die Erstellung der UIs bzw. der Logik konzentrieren kann.

Zudem hat knockoutJS keine Abhängigkeiten zu anderen Frameworks, unterstützt (laut Webseite) sogar den IE ab 6+ und kann trotzdem gut zusammen mit jQuery verwendet werden.

Wer das Beispiel mal ausprobieren will, kann dies gerne auf jsFiddle tun.

Im nächsten Beitrag betrachten wir AngularJS. Ein weiteres spannendes Framework, welches ebenfalls Konzepte wie Data Binding unterstützt, aber zusätzlich noch weitere nette Features mitbringt.

Stay tuned! 🙂