Přejít k navigační liště

Zdroják » JavaScript » Zbavte se snadno jQuery špaget s KnockoutJS

Zbavte se snadno jQuery špaget s KnockoutJS

Články JavaScript, Různé

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.

Komentáře

Subscribe
Upozornit na
guest
20 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
DM

Pro zájemce o tuto oblast doporučuji alternativní projekt http://angularjs.org od Googlu. Zvažoval jsem několik MVC JavaScriptových frameworků(včetně Knockoutu), AngularJS mi sedl nejvíce …

Tomas

Taky jsem pouzival angularJS a byl jsem s nim spokojenej. Daji se v tom uzasne jednoduse psat javascriptovy aplikace.

Jen si clovek musi uvedomit, ze u techto frameworku, kde se HTML-View vlastne renderuje az v javascriptu, se ta stranka vubec nezobrazi, pokud uzivatel nebude mit zapnuty javascript. Takze kdyz nekdo chce delat aplikaci, ktera ma byt zobrazitelna i s vypnutym javascriptem, tak mu to podobne knihovny znemozni. Tahle informace mi v tom clanku trochu chybi

Petrrr

„Takze kdyz nekdo chce delat aplikaci, ktera ma byt zobrazitelna i s vypnutym javascriptem, tak mu to podobne knihovny znemozni. Tahle informace mi v tom clanku trochu chybi“

To snad ne, to neni vsem jasne? O tom ze ma uzivatel vypnuty js ani nemluvne. Maximalne co bych pro tohodle uzivatele udelal je:

<noscript>Zapni si JS, jinak bye!</noscript>

smot

Paranoia je strašná věc. Ale různé reklamy a prvky velkých bratrů ještě horší.

#

Tak ja bych zas udelal papa tve strance, ze predpokladu, ze by nebyla zcela unikatni obsahem.

Čelo

Rozděloval bych klasické stránky a aplikace.

Petrrr

Zajimalo by me, jestli autor clanku zkousel AngularJS a pokud ano, jestli by byl tak laskav a napsal proc vyhral Knockout :)

Slysel jsem o AngularJS, ale zatim jsem si ho v praxi nevyzkousel.

RDPanek

V AngularJs jsem jiz napsal malou aplikacku – je fajn mít architekturu na straně klienta, ale i tak bych rád uvítal článek někoho zkušenějšího o Angularu, nebo rozbor jednotlivých frameworku.

Petrrr

Tyjo, tech JS MVC frameworku teda je!

http://codebrief.com/2012/01/the-top-10-javascript-mvc-frameworks-reviewed/

Sry za spam :)

Srigi

Zaujima ma ako je na tom KO z hladiska komunity a ekosystemu. Teraz sa vela venujem Backbone.js a je vidiet, ze je to uz zavedena kniznica – daju sa najst cele blogy alebo kvalitne blogposty, vznikli a su udrzovane rozsiahle frameworky, ktore akumuluju best-practises, kopec veci je uz vyriesenych na StackOverflow.

Je rovnaka situacia aj okolo KO, alebo Angular?

Jiří Landsman

Navíc bude nyní Knockoutjs distribuován v základních templatech pro asp.net mvc aplikace takže asi nějakou budoucnost mít bude :)

Vlada

S timto pristupem se do tagu zapisuji „nevalidni“ atributy. Existuje nejake DTD podle ktereho by byl pote dokument HTML-valid?

Martin Hassman

To není pravda, ty tagy s prefixem „data-“ jsou validní. HTML validátory s tím budou počítat (a vlastně už začínají).

Vlada

Mel jsem spis na mysli Angular, ktery pouziva atributy s prefixem „ng-„.

Vlada

… beru zpet – nyni koukam, ze Angular umoznuje take prefix „data-ng-“ …

Etermep

nezahrnuje

Oldřich Vetešník

Tož supr, díky, něco podobného jsem hledal, zkoušel jsem Ember.js a to mi přišlo zase moc opinionated, kdežto tohle je víc „udělej si sám“. :)

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.