Zbavte se snadno jQuery špaget s KnockoutJS

Pro oživení webů je dnes běžné použití frameworku jQuery. Ten spoustu věcí usnadňuje, ale problém udržovatelné struktury aplikace vůbec neřeší. Kdo pomocí něj zkoušel napsat něco složitějšího, dá mi zapravdu, že programátor může snadno skončit s ukázkovým „spaghetti kódem“, ve kterém je těžké se vyznat a špatně se udržuje.

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.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 20

Přehled komentářů

DM Mohu doporučit i alternativu AngularJS ...
Tomas Re: Mohu doporučit i alternativu AngularJS ...
Petrrr Re: Mohu doporučit i alternativu AngularJS ...
smot Re: Mohu doporučit i alternativu AngularJS ...
# Re: Mohu doporučit i alternativu AngularJS ...
Čelo Re: Mohu doporučit i alternativu AngularJS ...
Petrrr Re: Mohu doporučit i alternativu AngularJS ...
RDPanek Re: Mohu doporučit i alternativu AngularJS ...
Petrrr Re: Mohu doporučit i alternativu AngularJS ...
Jan Marek Re: Mohu doporučit i alternativu AngularJS ...
srigi Ekosystem Knockout
Jan Marek Re: Ekosystem Knockout
Jiří Landsman Re: Ekosystem Knockout
Vlada A co s HTML validitou?
Jan Marek Re: A co s HTML validitou?
Martin Hassman Re: A co s HTML validitou?
Vlada Re: A co s HTML validitou?
Vlada Re: A co s HTML validitou?
Etermep Re: A co s HTML validitou?
vetesnik Re: Zbavte se snadno jQuery špaget s KnockoutJS
Zdroj: https://www.zdrojak.cz/?p=3666