Zatímco jQuery se snaží být poměrně univerzální, Knockout řeší jednu jedinou věc – přenos stavu komponenty do uživatelského rozhraní a zpět. K tomu využívá návrhového vzoru Model – View – View Model (MVVM) a techniky obousměrného bindování hodnot z modelu do uživatelského rozhraní a zpět. Všechno ostatní (např. ajax, animace…) nechává na jQuery či libovolném jiném frameworku, který si zvolíte.
Základy práce s Knockout
Při práci s Knockoutem vytváříme dvě části – HTML šablonu a view model v JavaScriptu. Začneme HTML šablonou.
<p>Name: <input data-bind="value: name"></p> <p>Hello <span data-bind="text: name"></span></p>
Elementy, na kterých bude Knockout něco zajímavého provádět, obohatíme atributem data-bind. Inputu v příkladu je nabindovaná proměnná modelu name na atribut value. Do value se tedy nejdříve načte výchozí hodnota z modelu a naopak v případě změny value je hodnota aktualizována i v modelu. Při změně stavu modelu se automaticky upraví i text spanu.
var viewModel = {
name: ko.observable("World") // World je výchozí hodnota
};
Modelem pro tento kus HTML kódu se stane prostý javascriptový objekt. Nastavíme mu vlastnost name. Protože počítáme s tím, že tuto hodnotu může UI měnit, použijeme funkci ko.observable, která vytvoří objekt, který to zvládne.
// získání hodnoty
viewModel.name();
// nastavení hodnoty
viewModel.name('new value');
Pomocí funkce ko.applyBindings model aktivujeme. Knockout začne hledat svoje data-bind atributy ve výchozím stavu po celém dokumentu. To lze případně omezit předáním DOM elementu v druhém parametru.
ko.applyBindings(viewModel);
Jednoduchý nákupní košík
Použití frameworku Knockout jsem si vyzkoušel na nákupním košíku z webu kapely Zrní. Ten byl původně implementován pouze pomocí jQuery, můžu tedy oba přístupy snadno porovnat. Zjednodušenou verzi košíku ukážu v tomto článku.
Košík obsahuje upravitelný seznam položek a ukazuje celkovou cenu objednaného zboží. Vytvořím tedy pro něj odpovídající konstruktorovou funkci a využiji ko.observableArray pro položky a celková cena bude dopočítávanou hodnotou. K vytvoření dopočítávané hodnoty slouží funkce ko.computed. Ta funguje tak, že jí podstrčíme callback, který se okamžitě spustí. Při té příležitosti Knockout získá výchozí hodnotu a seznam závislostí computed hodnoty. Při změně observable závislostí je znovu callback spuštěn a dopočítávaná hodnota aktualizována.
function BasketViewModel() {
this.items = ko.observableArray();
this.totalPrice = ko.computed(function () {
var items = this.items();
var totalPrice = 0;
for (var i = 0; i < items.length; i++) {
totalPrice += items[i].count() * items[i].price;
}
return price;
}, this);
}
var model = new BasketViewModel();
Protože u položky košíku budu chtít měnit počet objednávaných kusů, vytvořím pro položku další vnořený model.
function BasketItemModel(name, price) {
this.name = name;
this.price = price;
this.count = ko.observable(1); // výchozí hodnota 1
}
Jak lze přidávat další položky do košíku, ilustruje funkce addToBasket.
/**
* @param {BasketViewModel} basketModel
* @param {Object} item
*/
function addToBasket(basketModel, item) {
var itemModel = new BasketItemModel(item.name, item.price);
basketModel.push(itemModel);
}
<h2>Košík</h2> <p data-bind="visible: items().length == 0">Zatím nemáte vybráno žádné zboží.</p> <div data-bind="visible: items().length != 0"> <table> <thead> <tr> <th>Název</th> <th>Množství</th> <th>Cena/kus</th> </tr> </thead> <tbody data-bind="foreach: items"> <tr> <td data-bind="text: name"></td> <td><input type="number" data-bind="value: count"></td> <td><span data-bind="text: price"></span> Kč</td> </tr> </tbody> </table> <p>Celková cena: <span data-bind="text: totalPrice"></span> Kč</p> </div>
HTML šablona je vcelku přehledná. Je v ní vidět schovávání elementů v závislosti na počtu položek v košíku, procházení observable array pomocí foreache, bindování hodnot modelů položek a zobrazení celkové ceny.
Závěr
Při přepisu košíku z frameworku jQuery se mi kód při kompletním zachování funkčnosti zkrátil asi o třetinu. Za důležitější ale považuji to, že je v něm řešena pouze logika toho, co se má dít, nikoliv prezentace dat uživateli. Jak se má stav košíku zobrazovat, je definováno deklarativně v HTML šabloně.
Velmi příjemné bylo, že jsem se v kódu zbavil navěšování událostí a nutnosti myslet na to, co při jaké události musím ještě přepočítat. I proto pro mě bylo jednodušší vymyslet nový kód než použít ten původní.
Výhodné je, že Knockout nevyžaduje změny v architektuře aplikace, lze jej začlenit do existující aplikace a usnadnit si s ním pro začátek práci na jedné komponentě.
Díky své jednoduchosti a výborné dokumentaci se dá Knockout velice rychle naučit. Když mu věnujete jedno odpoledne, do budoucna vám může ušetřit spoustu práce. Začít můžete právě teď v interaktivních tutoriálech Knockoutu.


Přehled komentářů