Vue.js: 5 - filtry

Trocha teorie

V dnešní části seriálu se podíváme na to, jak formátovat výstup do HTML. Může se nám stát, že máme nějaké hodnoty ve formátu, se kterým se nám dobře pracuje v kódu, ale pro uživatele je mnohem přívětivějsí, když uvidí data zformátována jinak. Typickým příkladem jsou velká čísla, datum a čas, atd., kde je formát používaný v kódu pro normálního uživatele poněkud nepřehledný.

Existuje několik možností, jak toho docílit. První možností by bylo mít v datech pro stejný údaj uloženy dvě hodnoty, jednu pro kód, a druhou pro zobrazení uživatelům. To je sice možné, relativně jednoduché, ale ne úplně efektivní řešení, protože tímto vlastně duplikujeme hodnotu a máme ji uloženou v ruzných tvarech na dvou různých místech. Naštěstí Vue nabízí tzv. Filtry, které řeší přesně tento problém - tj. konvertují data z jednoho formátu do jiného pro použití v šablonách, ale nijak nám nemění zdrojová data.

Tolik k teorii, a můžeme se pustit do vlastní implementace. Naše aplikace zobrazuje aktuální čas kliknutí, ale namísto data v nějakém rozumném formátu vypisuje ISO timestamp, což je pro uživatele nepraktické a "ošklivé". Naším cílem je zformátovat datum tak, aby bylo pro uživatele čitelné a takové, na jaký je zvyklý.

Změna v kódu předchozí kapitoly

V předchozí verzi aplikace jsme ukládali data do pole hodnot jako UNIX timestampy, nicméně kvůli kompatibilitě se všemi prohlížeči (specificky mám na mysli Safari) a kvůli názornosti kódu změníme aplikaci tak, aby ukládala datum v ISO formátu (YYYY-MM-DDTHH:mm:ss.xxxZ)a nikoliv jako UNIX timestamp.

Změníme tedy řádek this.items.push(Date.now()); následovně:

var now = new Date();  // create new Date object instance

this.items.push(now.toISOString());  // and push ISO string to items

Implementace filtru

V oficiální dokumentaci k filtrům zjistíme, že na naší komponentě je možné vyrobit novou property s názvem filters, kde jsou filtry definované. Každý filtr poté bude definovaný jako funkce. Vzhledem k tomu, že vyrábíme filtr pro formátování data, pojmenujeme jej date

Přidáme tedy tento nový kód do naší komponenty:

filters: {
    date: function (value) {
        return value;
    }
},

Tímto jsme si definovali nový filtr, co jsme přesně napsali vysvětlíme za malou chvíli. Předtím ještě řekneme aplikaci, aby tento filtr používala. V naší smyčce který vypisuje časy kliknutí změnímě kód takto

<li v-for="(item, index) in items" v-on:click="removeClick(index)">
    {{ index }}: {{ item | date }}
</li>

Jediné co se změnilo je část {{ item | date }}, kde máme uvedenou hodnotu v proměnné item, poté znak | (pipe, v češtině jsem pro tento znak slyšel výraz "svislítko"), který dává Vue instrukce, že po hodnotě bude následovat nějaký filtr. A nakonec je název vlastního filtru. V podstatě tedy říkáme vezmi hodnotu proměnné "item" (ve které máme ISO timestamp), aplikuj na ní filtr "date" a tuto hodnotu vypiš.

Když nyní zobrazíme aplikaci, tak zjistíme, že se nic nezměnílo, a že jsou data vypsaná pořád jako timestampy. Je tedy nutné se podívat na to, jak se definuje filtr jako takový.

Jak již bylo zmíněno, každý filtr je definovaný jako funkce. V nejzákladnější variantě má funkce filtry jeden argument - to je hodnota, na kterou se filtr bude aplikovat. V našem případě to bude tedy ISO timestamp kliknutí.

Dále musí funkce filtru něco vracet - tím něčím je myšleno zkonvertovaná hodnota, kterou chceme zobrazit na stránce.

Když se podíváme na naši implementaci, tak zjistíme, že vlastně vracíme stejnou hodnotu jako kterou dostáváme, a že tedy k žádné konverzi nedochází

date: function (value) {
   return value;
}

Upravíme tedy funkci filtru tak, aby skutečné konvertovala timestamp na hezky zformátované datum a čas.

date: function (value) {
    var date = new Date(value); // create new instance of Date object from the given ISO string

    return date.toLocaleString(); // and return date&time formatted according to user language settings

}

kód není příliš komplikovaný a je okomentovaný. Jde jen o to, že nejprve si vytvořímé novou instanci nativního Javascriptového Date objektu, kterému předáme jako argument náš ISO string s datem kliku. A na druhém řádku tento zformátujeme pomocí funkce toLocaleString(), která datum zformátuje do tvaru dle jazykového nastavení operašního systému a prohlížeče, a vrátí zpět. Když si teď otevřeme aplikaci, tak by nám měla zobrazovat seznam kliknutí ve formátu, který je čitelný pro uživatele.

Další možnosti a využití filtrů

Samozřejmě je možné si s formátováním vyhrát, vyrobit si vlastní formát data s využitím metod na Date objektu . Podstatné je to, aby funkce filtru vždy vracela zformátovanou hodnotu.

Použití filtrů je skvělé například pro formátování čísel (přidání oddělovače tisíců, desetinná místa, apod.), či pro zformátování telefonního čísla tak, aby bylo vždy ve stejném formátu, PSČ, nebo třeba zobrazení ceny včetně DPH, možností využití je bezpočet.

Do filtrů je dokonce možné posílat i dalši argumenty a na jejich základě data formátovat, ale to si necháme až do jednoho z následujících dílů seriálu.

Na závěr ještě kompletní zdrojový kód dnešního dílu.

Vue.js: 4 - renderování seznamů

Další často se opakující operací je zobrazení seznamu objektů pomocí direktivy v-for. Toto se hodí například pokud budete mít aplikaci s databází uživatelů a chcete zobrazit jejich seznam, ale samozřejmě to není jediné použití. Jedinou podmínkou je to, že budeme zobratovat nějaké pole prvků (pričemž v poli můžou být řetězce, čísla, ale i další pole či objekty)

Pro vyzkoušení konceptu opět rozšíříme naši vzorovou aplikaci, a přidámne další data property items:

data: function() {
    return {
        heading: 'Click Counter',
        message: 'This component shows how many time you clicked on the button',
        clickCounter: 0,
        items: [1,3,5,7,9]
    }
},

data property items není nic jiného, než pole číselných hodnot. Budeme nyní chtít toto pole hodnot vypsat do stránky jako ul -> li seznam. Rozšíříme tedy naší sablonu a přidáme do ní kód pro vygenerování seznamu

    <ul>
        <li v-for="item in items">
            {{ item }}
        </li>
    </ul>

ul je jen klasický root element pro HTML seznam, ale na elementu li máme použitou direktivyu v-for, kterou si opět podrobně rozebereme <li v-for="item in items">

Jak je již zřejmé, v-for je název direktivy, a podstatné budou opět hodnoty v závorkách, tedy item in items. Tímto frameworku říkáme, aby se podíval do komponenty, hledal zde data property items, a pokud tato bude pole, pro každou jednotlivou položku v HTML stránce vytvoří nový element li a zároveň hodnotu té konkrétní položky uloží do lokální proměnné item

S proměnnou item dále můžeme pracovat, a uvnitř elementu li ji používat. V našem případě ji pouze vypisujeme pomocí {{ item }}. Výsledkem by tedy měl být HTML kód, ul -> li konstrukce, která bude mít 5 položek a vypíše pod sebe hodnoty 1,3,5,7,9

Přidávání položek ze seznamu

nyní sice můžeme vypsat pole statických hodnot, ale abychom měli funkční aplikaci, bude se hodit, když budeme umět prvky do seznamu dynamicky přidávat a nebo je odebírat.

Pro začátek vyprázdníme data property items: [], aby aplikace neměla při úvodním načtení žádné prvky ke zobrazení. Máme aplikaci, která nám počítá kolikrát jsme kliknuli na tlačítko, takže se rozhodneme, že chceme zaznamenávat čas každého kliknutí. Co tedy musíme udělat - v okamžiku, kdy klikneme na tlačítko, tak zjistíme aktuální čas, a vložíme jej do pole items.

Díky tomu, že my již nasloucháme na stisknutí tlačítka a zvyšujeme počítadlo o jedničku, využijeme stejnou funkci, tj. buttonClick, a jen ji příslušně rozšíříme:

methods: {
    buttonClick: function() {
        this.clickCounter++;
        this.items.push(Date.now())
    }
}

Když nyní budeme klikat na tlačítko, tak namísto pevně definovaných čísel nám budou do seznamu naskakovat čísla vytvořená funkcí Date.now(). Jedná se o statickou funkci standardího JavaScriptového objektu Date, která vrací aktuální počet milisekund od počátku UNIX epochy, tj. od 1.1.1970.

Není to však úplně uživatelsky přívětivé, mnohem lepší by bylo mít možnost zobrazit datum a čas v nějaké "polidštěné" podobě. Než se však pustíme do tohoto úkolu, ukážeme si, jak položky ze seznamu odebrat.

Odebírání položek se seznamu

Položku ze seznamu budeme chtít odebrat tím, že na ní klikneme (zároveň budeme chtít i udělat to, že pokud odebereme položku ze seznamu, snížíme i počítadlo o 1). Abychom toho dosáhli, nejprve upravíme šablonu s v-for direktivou

<li v-for="(item, index) in items">

původní item jsme zde nahradili konstrukcí (item, index). Tímto Vue říkáme, že do proměnné item vloží každou jednotlivou položku z pole items (toto se od předchozího příkladu nemění), ale zároveň zde definujeme i novou proměnnou index. Pokud požijeme tuto kontrukci, tak Vue pro každou iteraci do lokální proměnné index vloží právě index té konkrétní položky. Toto bude lépe pochopitelné na ucelenějším příkladě. Upravíme kód takto:

<li v-for="(item, index) in items">
    {{ index }}: {{ item }}
</li>

když teď budeme klikat na tlačítko, tak se první položka zobrazí jako 0: timestamp, druhá jako 1: timestamp, apod., protože zde zobrazujeme jak index, tak samotnou hodnotu položky.

Zatím však stále nemáme implementovanou funkcionalitu pro odebírání položek se seznamu. To uděláme následujícím způsobem

<ul>
    <li v-for="(item, index) in items" v-on:click="removeClick(index)">
        {{ index }}: {{ item }}
    </li>
</ul>

direktiva v-for zde zůstává, ale na položku li přidáváme již známou direktivu v-on:click, a při kliknutí spustíme funkci removeClick s parametrem index (přičemž index je práve index té konkrétní položky v poli items)

Poslední věc, která nám chybí je tedy implementace vlastní metody removeClick. Do sekce methods tedy přidáme implementaci této metody:

removeClick: function(index) {
    this.clickCounter--;
    this.items.splice(index, 1);
}

tato metoda (funkce) nám říká, že snížíme počítadlo kliků o jedničku, a na druhém řádku odebereme jednu položku z data property items pomocí funkce splice(), což je standardní funkčnost JavaScriptu pro odstranění položek z pole, viz https://www.w3schools.com/jsref/jsref_splice.asp . Díky tomu, že do funkce posíláme hodnotu index, víme, jakou položku máme z pole odstranit.

Na závěr ještě kompletní zdrojový kód k této části seriálu, a v příští lekci si ukážeme, jaké máme možnosti formátování data a času, aby nám aplikace neukazovala jen "syrové" timestampy.

Vue.JS: 3 - Podmíněné zobrazování

V předchozím díle jsme použili naši první direktivu v-on, dnes se podíváme na to, jaké další direktivy se nám budou hodit v našich aplikacích, a konkrétně na direktivy pro podmíněné zobrazování obsahu. V podstatě se jedná o analogii na klasické konstrukce dostupné v téměř jakémkoliv programovacím jazyce, a to if, else a else if

v-if

Jednou z nejčastěji používaných direktiv bude direktiva pro podmíněné zobrazení nějakého obsahu. Pomocí v-if budeme schopní zobrazit HTML tagy, pokud bude splněna zadaná podmínka. Řekněme, že povolíme na tlačítko kliknout maximálně 5x, a poté by mělo toto tlačítko zmizet. Jak na to ? Náš button element rozšíříme právě o direktivu v-if

<button v-if="clickCounter < 5" v-on:click="buttonClick()">Click Me</button>

Schválně zkuste klikat na tlačítko ... v okamžiku, kdy na něj kliknete 5x, tak zmizí. Znovu si detailně rozpitváme použitou direktivu v-if="clickCounter < 5". v-if je název direktivy, a uvnitř uvozovek máme logický javascriptový výraz. Direktiva funguje tak, že tento výraz vyhodnotí, a zobrazí element na kterém je použitá pokud je výraz vyhodnocený jako true.

Náš výraz uvnitř uvozovek je clickCounter < 5. clickCounter je data property, naše počítadlo, které se zvyšuje od jedničku po každém kliknutí na tlačítko. Takže my zde máme nastaveno, že se tlačítko zobrazí pouze pokud bude počítadlo menší než 5, a poté tlačítko zmizí.

Důležité je uvědomit si, že není nutné direktivu aplikovat pouze na button, ale je možné ji aplikovat na jakýkoliv nadřazený element. Můžeme tedy aplikaci upravit takto:

...
<div v-if="clickCounter < 5" >
    <button v-on:click="buttonClick()">Click Me</button>
    Clicked {{ clickCounter }} times.
</div>
...

Co se stane teď je, že zmizí nejenom samotné tlačítko, ale i celý div na který aplikujeme direktivu, a to včetně textu "Clicked X times"

v-else

Pro lepší uživatelské komfort naší aplikace budeme nyní chtít uživateli zobrazit poté co klikne 5x zprávu o tom, že dále již není možné pokračovat. K tomu použijeme direktivu v-else. Upravíme tedy kód

<div v-if="clickCounter < 5" >
    <button v-on:click="buttonClick()">Click Me</button>
    Clicked {{ clickCounter }} times.
</div>
<div v-else>
    Sorry. You already clicked too many times.
</div>

Do kódu jsme teď přidali nový div, který má aplikovanou direktivu v-else. Tato direktiva nemá žádné parametry, a chová se jako přesný opak poslední použité direktivy v-if. Takže pokud predchoí v-if direktiva byla vyhodnocena jako true a zobrazuje svůj obsah, v-else bude vyhodnocena jako false a svůj obsah nezobrazí (a naopak).

v-else-if

Pro úplnost dodáme ještě direktivu v-else-if. Aplikaci upravíme takto:

<div v-if="clickCounter < 5" >
    <button v-on:click="buttonClick()">Click Me</button>
    Clicked {{ clickCounter }} times.
</div>
<div v-else-if="clickCounter < 8" >
    <button v-on:click="buttonClick()">Click Carefully</button>
    Clicked {{ clickCounter }} times.
</div>
<div v-else>
    Sorry. You already clicked too many times.
</div>

Původní v-if podmínka zůstává zachována, ale mezi v-if a v-else jsme ještě vložili další div s direktivou v-else-if="clickCounter < 8". Aplikace se tedy teď bude chovat tak, ze pokud jste kliknuli na tlačítko méně nez 5x, zobrazí první div s tlačítkem "Click Me". Pokud jste klikli 5x a více, první v-if se vyhodnotí jako false, a Vue přejde k vyhodnocení další podmínky, což je v našem případě v-else-if="clickCounter < 8". Pokud jste tedy klikli alespoň 5x, ale zároveň méně jak 8x, aplikace zobrazí jiné tlačítko "Click Carefully". A konečně pokud jste kliknuli osmkrát a více, aplikace zobrazí pouze zprávu že jste klikli příliš mnohokrát, a žádné tlačítko nezobrazí

v-show

v-show je direktiva, která má naprosto stejnou syntaxi jako v-if, liší se však v tom, jak ji framework vkládá do HTML.

Pokud je podmínka ve v-if vyhodnocena jako false, tak je příslušný element úplně odstraněn z DOMu stránky, a když si zobrazíte zdrojový kód přes dev konzoli, tento element zde vůbec nenajdete.

Když však namísto v-if použijete v-show, element bude do HTML kódů renderovaný, ale bude skrytý pomocí CSS stylu display: none;. To může být v některých případěch výhodné. Například pokud se vám často mění podmínka pro v-if, a direktiva je použitá na nějakou složitejší HTML strukturu, prohlížeč musí při každé změně podmínky element odstranit nebo naopak přidat do DOMu. Oproti tomu při použití v-show je tento element v DOMu permanentně, a pouze se zobrazuje a skrývá pomocí CSS, cože je pro prohlížeč méně náročná operace.

Na druhou stranu, v-show má o něco vyšší režii při prvotním vykreslení stránky - právě proto, že se do DOMu renderuje vždy, a případně se skryje. Oproti tomu v-if se bude generovat pouze v případě, že se skutečně má zobrazit.

Zda je výhodnější použít v-if nebo v-show záleží na konkrétních případech, ale je nutné pamatovat na to, že v-show neumí pracovat s v-else nebo v-else-if, a jeho použití je tak do jisté míry omezenější.

Pokud bychom chtěli přepsat naší aplikaci za použití v-show místo v-if, vypadalo by to asi takto:

    <div v-show="clickCounter < 5" >
        <button v-on:click="buttonClick()">Click Me</button>
        Clicked {{ clickCounter }} times.
    </div>
    <div v-show="clickCounter >= 5 && clickCounter < 8" >
        <button v-on:click="buttonClick()">Click Carefully</button>
        Clicked {{ clickCounter }} times.
    </div>
    <div v-show="clickCounter >= 8">
        Sorry. You already clicked too many times.
    </div>

kvůli tomu, že v-show nepodporuje v-else-if ani v-else, je zápis o něco krkolomnější, protože namísto v-else-if="clickCounter < 8" musíme psát v-show="clickCounter >= 5 && clickCounter < 8". Zároveň je obtížnější tento kód měnit, protože jednu podmínku je nyní nutné měnit na více místech.

Na závěr ještě odkaz na zdrojové kódy

Vue.JS: 2 - Základní koncepty

V prvním díle seriálu jsme si ukázali, jak vytvořit první triviální aplikaci, ale ještě než se pustíme dále, musíme probrat několik základních konceptů.

Vue komponenty

Základní jednotkou pro vývoj ve Vue.JS jsou tzv. komponenty. Komponentu můžeme chápat jako HTML tag, který může mít nějaké vylepšené/rozšířené chování či vzhled. Komponenty jsou specifikované šablonou ("jak komponenta vypadá") a chováním ("co se stane když vykonáme nějakou událost na komponentě, např. klikneme na tlačítko")

Šablony

Šablonu komponenty definujeme pomocí HTML (a CSS). Stylování pomocí CSS necháme v tuto chvíli stranou a zaměříme se na HTML část. Když vezmeme příklad z předchozí kapitoly, tak šablona naší komponenty vypadala takto:

<div id="vue-app">
    {{ message }}
</div>

Pro lepší názornost teď šablonu rozšíříme

<div id="vue-app">
    <h1>{{ heading }}<h1>
    <p>
        {{ message }}
    </p>
</div>

Tato komponenta teď zobrazí v nadpise text, který definujeme v data objektu jako heading, a zároveň zobrazuje stejnou message property jako v předchozím případě.

Chování

Chování komponenty je definováno v JavaScriptové sekci. Naše komponenta má prozatím velice jednoduché chování, a to že zobrazuje pevně zadaný text. Aby fungoval náš příklad, musíme JavaScript komponenty rozšířit o data property heading

    var app = new Vue({
        el: '#vue-app',
        data: function() {
            return {
                heading: 'Click Counter',
                message: 'This component shows how many time you clicked on the button',
                clickCounter: 0
            }
        }
    });

Toto jak jistě uznáte není vůbec zajímavé a prakticky téměř k ničemu, takže komponentu dále rozšíříme. Jak je možná zřejmé z textů, vyrobíme si komponentu, která bude ukazovat počet kliknutí na tlačítko.

Do JS kódu jsme přidali i data property clickCounter, kterou použijeme pro uchování informace o tom, kolikrát jsme kliknuli na tlačítko. Výchozí stav bude 0.

Co nám chybí je zobrazení počítadla a tlačítko, na které bude možné kliknout. Velmi jednoduše přidáme do šablony kód pro vypsání další data property clickCounter a HTML markup pro tlačítko:

...
<p>
    {{ message }}
</p>
<button>Click Me</button>
Clicked {{ clickCounter }} times.

Naše komponenta bude vypadat nějak takto
clickCounterComponent.jpg
ale stále jí něco chybí - a to funkcionalita která při kliknutí na tlačítko zvýší počítadlo o 1.

Naslouchání na události

Abychom dosáhli našeho cíle, musíme zajistit, že se při kliknutí na tlačítko provede nějaká akce (zvýšení počítadla o 1). Musíme tedy nastavit, že kliknutí na tlačítko provede nějakou operaci. HTML pro tlačítko rozšíříme tímto způsobem:

<button v-on:click="buttonClick()">Click Me</button>

Co je však ono v-on:click="buttonClick()" ? Jedná se o tzv. Vue direktivu, která frameworku říká, co ma provést při konkrétní události. Pokud direktivu rozpitváme ještě více, dostaneme několik částí:

  • v-on: zápis pro Vue direktivu, definujeme, že budeme naslouchat na nějakou událost která se na HTML elementu stane
  • click je název vlastní události na kterou chceme reagovat. V našem případě je to klik na tlačítko, ale může to být jakákoliv událost, kterou prohlížeč dokáže detekovat, například keyup, mouseover, focus, apod.
  • ="buttonClick()" a zde nastavujeme, jaká akce se má provést v případě, že dojde k události, v našem případě budeme volat funkci buttonClick()

Celý zápis by se tedy dal do "lidské řeči" přeložit jako "při kliknutí na toto tlačítko spusť funkci buttonClick()"

Pokud byste nyní aplikaci zkusili spustit a kliknete na tlačítko, v konzoli prohližeče vyskočí chyba

[Vue warn]: Property or method "buttonClick" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.`

je to logické, protože nám ještě chybí poslední část aplikace, a tou je právě implementace funkce buttonClick() která se má spustit při kliknutí na tlačítko. Pokud z šablony voláme nějakou funkci, Vue se podívá do komponenty, která šablonu používá, a hledá na ni funkci s příslušným názvem. V našem případě však zatím žádnou takovouto funkci definovanou nemáme.

Kód komponenty tedy musíme dále rozšířit a implementovat zde naši funkci (ve Vue označovanou jako metoda) buttonClick.

    ...
        clickCounter: 0
    }
},
methods: {
    buttonClick: function() {
        this.clickCounter++;
    }
}

Přidali jsme novou sekci methods do komponenty, a v ní jsme definovali buttonClick jako funkci. Obsahem funkce je pouze this.clickCounter++;. Další z Vue konceptů je ten, že veškerá data a metody jsou v rámci komponenty přístupné pomocí klíčového slova this. Lze to chápat tak, že pokud jste v JavaScript kódu komponenty, tak this vždy odkazuje na instanci té komponenty. Z HTML šablony se k datům a metodám přistupuje bez this.

Jediné, co tedy v rámci metody děláme je, že zvyšujeme data property clickCounter o 1. Pokud tedy klikneme na tlačítko, zvyšíme počítadlo o 1.

Reaktivita

Pokud nyní budete klikat na tlačítko, uvidíte, že se dochází k okamžitému zvýšení počítadla na stránce s aplikací. Není potřeba nikde definovat, že se má překreslit stránka, ale stará se o to sám framework. Komponenta totiž vždy zobrazí aktuální hodnotu data property. Toto má na svědomí koncept, který je označován jako Reaktivita. Pro podrobný technický popis jak tento koncept funguje ve Vue můžete navštívit oficiální dokumentaci https://vuejs.org/v2/guide/reactivity.html , ale pro nás je nyní nejpodstatnější to, že jakoukoliv změnu v data property framework automaticky detekuje a překreslí dle toho stránku v prohlížeči.

Aby reaktivita ve Vue fungovala správně, je nutné jednotlivé data properties definovat předem, a to i v případě, že je jejich hodnota prázdná. Vue bude díky tomu o těchto datech vědět, a bude automaticky detekovat jejich změny.

Závěr

naše aplikace toho pořád moc neumí, ale my bychom už měli zvládat dva základní koncepty, bez kterých se dále neobejdeme, a to zobrazování dat v šabloně, a reakce na události. V příští části tyto základní koncepty ještě rozšíříme a probereme další nutné direktivy.

Na závěr ještě odkaz na zdrojový kód:
https://github.com/becquerel/vue-tutorial/blob/master/example2/index.html

Vue.JS: 1 - Úvod

Úvod

Moderní webová aplikace se dnes již neobejde bez trochy toho JavaScriptu. Já sám jsem byl dlouhá léta zastáncem teorie, že JavaScript je vhodný pro předběžnou validaci formulářů (přičemž skutečná validace stejně probíhá na backendu), případně pro ruzné schovávání a zobrazování delších bloků textů, které není třeba mit zobrazeny pořád. Časem jsem k tomu přidal používání jQuery pluginů, například pro datepicker nebo colorpicker. Nicméně za posledních několik let jsem byl nucen svůj názor zásadně přehodnotit, a dnes můžu říct, že si bez JavaScriptu už nedokážu svoji práci představit.

Existuje celá řada frameworků (či knihoven), které mají práci s JavaScriptem ulehčovat. Troufnu si říct, že nejpoužívanějšími jsou Angular a React, ale těm se teď věnovat nechci. Místo toho se chci zaměřit na framework, který byl až donedávna poměrně neznámým, a tím je Vue.JS (https://vuejs.org/), ale rychle získává na popularitě.

U Vue je vidět silná inspirace původním Angularem (podobná syntaxe), ale narozdíl od Angularu se nejedná o plnohodnotný framework, ale spíše o knihovnu, ktera řeší pouze renderování HTML. Tím se zase mnohem více blíží Reactu, který má podobné zaměření.

Seriál počítá s použitím aktuální verze Vue.JS, což je v tuto chvíli 2.3.3

Disclaimer 1: předpokladem je alespoň základní znalost HTML, CSS a JavaScriptu. Nebudu vysvětlovat obecné koncepty, co je to DOM, události, syntaxi JavaScriptu jako takového, apod. Na druhou stranu se však budu snažit celý seriál pojmout jako intro do jiného způsobu práce s JavaScriptem, snažit se vysvětlit základní koncepty polopaticky, někdy i za cenu nepřesného zjednodušení. Ideální cílovou skupinou tak mohou být vývojáři, kteří momentélně pracují v jQuery nebo vanilla javascriptem, a chtějí si rozšířit obzory (ale doufám, že bude seriál prospěšný i ostatním)

Disclaimer 2: občas budu používat porovnání s Reactem či Angularem. Podotýkám, že nemám nic ani proti jednomu z těchto frameworků a oba aktivně používám. Neříkám, že Vue je lepší nebo horší, ale budu zmiňovat spíše jeho výhody.

Veškeré zdrojové kódy k ukázkám budou dostupné na GitHubu

Proč Vue ?

Výhodou pro použití Vue je jeho relativní jednoduchost, rychlost a nízké bariéry pro efektivní vývoj. Je možné napsat funkční aplikaci či komponentu, a to velmi rychle, čímž se liší od Angularu či Reactu. I tyto dva frameworky ušly kus cesty, ale dle mého názoru je přece jen začít s Vue jednodušší.

Vue není plnohodnotný framework, jedná se, podobně jako u Reactu, pouze o knihovnu, která řeší jednu věc, a tou je renderování HTML. Je samozrejmě možné jej použít i pro větší SPA aplikace, ale vyžaduje to již nějaké zkušenosti s návrhem JS aplikací, protože Vue vývojáře nenutí dodržovat pevně danou strukturu. Kde však Vue bude skutečně excelovat jsou jednotlivé malé komponenty, části stránky, které můžou mít svoji vlastní logiku, ale jsou relativně nezávislé na zbytku stránky. Typickým příkladem může být například komponenta pro vyhledávání (search box, který bude při psaní rovnou zobrazovat výsledky vyhledávání), nebo emailový kontaktní formulář vložený do patičky stránky. Dalším příkladem užitečné komponenty by mohlo být nějaké dynamické menu, nebo klidně i accordion (https://www.w3schools.com/howto/howto_js_accordion.asp)

Jak začít

Jednoduchost, s jakou je možné vytvořit si svoji první Vue aplikaci, považuji za velmi silnou stránku. Když jsem poprvé zkoušel React, tak se přiznám, že jsem jako backenďák tento první pokus vzdal. Nutil mě totiž nainstalovat celou řadu podpůrných technologií, a nebyl jsem schopný je všechny takto najednou absorbovat. Podobné to bylo v případě Angularu. Časem jsem se k těmto technologiím prokousal, ale jako první zkušenost s JS frameworky to skutečně nebylo to pravé.

Oproti tomu, pokud chcete začít s Vue, tak pro prvotní experimenty stačí importovat vlastní framework z CDN a rovnou začít psát. Jako první experiment vytvoříme klasickou "Hello World" aplikaci ve Vue.JS. Jak na to ? Velmi jednoduše. Do HTML stránky vložíme standardní HTML kód, který bude sloužit jako šablona, či "kontejner" pro naši aplikaci.

<div id="vue-app">
    Hello Vue !
</div>

Když nyní zobrazíte stránku, zobrazí se zde text "Hello Vue !". Tohle ale není žádný JavaScript, jedná se přece o úplně klasické HTML. Což je přesně ono, Vue ve své podstatě vychází z HTML, a dokáže "rozšířit" jeho chování. Abychom tedy udělali skutečnou Vue aplikaci, potřebujeme ještě importovat vlastní Vue, přidáme tedy jen externí JavaScript z CDN

...
<script src="https://unpkg.com/vue@2.3.3"></script>
</body>

UPDATE 2017-06-02 některé prohlížeče nedokáží fungovat s unpkg korektně. Pokud je to i váš případ, je možné adresu nahradit alternativní CDN, například https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js. Více informací na oficiálním webu https://vuejs.org/v2/guide/installation.html

a dále spustíme vlastní Vue aplikaci:

<script type="text/javascript">
    var app = new Vue({
        el: '#vue-app'
    });
</script>

Tato naše "aplikace" se vyznačuje tím, že nic nedělá, chová se úplně stejně, jako kdybychom zde žádný JavaScript neměli. Je to vlastně jen odstavec s textem uvnitř. Nicméně i tak několik komentářů:

  • náš div v HTML má nastaveno id="vue-app"
  • v okamžiku, kdy vytváříme novou Vue instanci, předáváme jako jeden z parametrů (v našem případě jediný parametr) el: '#vue-app'. Dle hodnoty el Vue pozná, který element v HTML stránce si má vzít "pod kontrolu". Takže my vlastně říkáme "nastartuj novou Vue aplikaci, která bude ovládat HTML element s id=vue-app"

Je sice hezké, že máme div, který je "pod kontrolou" Vue, ale zatím jsme skutečně ničeho nedosáhli. Změníme tedy aplikaci tak, aby místo statického textu zobrazovala text který načte z JavaScriptu. Nejprve rozšíříme naši Vue aplikaci (komponentu) o novou property data, takže naše komponenta pak bude vypadat nějak takto:

var app = new Vue({
    el: '#vue-app',
    data: function() {
        return {
            message: 'Hello from Vue !'
        }
    }
});

property data (jejíž hodnotou musí být funkce, která vrací javascriptový objekt) slouží, jak její název napovídá, k uložení dat / informací ke komponentě. V našem případě máme uloženou property message s hodnotou Hello from Vue !

Poslední věc, kterou uděláme - zobrazíme tento text, namísto původního fixního textu. V našem HTML změníme fixní text Hello Vue na {{ message }}

<div id="vue-app">
    {{ message }}
</div>

Jak bylo uvedeno výše, Vue má "pod kontrolou" celý html tag <div id="vue-app">, a tento zápis dává instrukci Vue frameworku, aby se podíval do komponenty která tento HTML tag ovládá, a hledal v ní data property message. V našem případě ji najde, a zde vypíše její hodnotu, což je v našem případě zpráva Hello from Vue !

Kompletní zdrojový kód

Námi vytvořená aplikace je skutečně triviální, má jen demonstrovat jednoduchost použití, nicméně někde je nutné začít. V dalším díle popíšu trochu podrobněji několik základních konceptů a vyrobíme aplikaci, která bude i něco dělat.

Zaklady prace s Gitem a nas workflow

Trocha teorie

Git je distribuovaný verzovací system, to znamena, ze kdyz se dela zakladni prikaz CLONE, tak si k sobe stahnete nejen aktualni verzi kodu, ale zaroven i kompletni historii. Protikladem k tomuhle je treba subversion, coz je jiny verzovaci system, ktery je centralizovany - je tam jediny "source of truth", nejaky jediny hlavni serverhlavni server.

U GITu je mozne mit tech hlavnich serveru vic. Coz na jednu stranu zvysuje robustnost, an druhou stranu je to zdrojem problemu pri jejich synchronizaci. Ale to vetsinou neresime, my git pouzivame hodne podobne jako centralizovany system - jediny a hlavni zdroj pravdy mame na bitbucketu, a vyvojari maji kopie (klony) u sebe.

Git umoznuje delat vetve (branche). To je proto, ze existuje nejaka produkcni verze kodu, ktera je nasazena na ostrem serveru, zpravidla na branchi s nazvem master. A potom muzete mit rozpracovane ruzne nove funkce, ktere jeste nejsou hotove ... ale je potreba si svoji praci nekam ukladat. Proto v gitu je mozne mit paralelne vedle sebe nekolik ruznych vetvi/verzi kodu. Kdyz se potom dela deploy do produkce, tak se nastavi, ze deploy vzdycky bere verzi kodu z master branche. Ale treba nejaky vyvojovy nebo testovaci server muze cist z branche jine.

V okamziku, kdy je ta nova funkce hotova a schvalena, tak je potreba ty branche nejak synchronizovat, spojit. To se dela pres tzv MERGE, kdy reknes ze "vsechno co je ted v branchi s nazvem feature/moje-nova- cool-feature nahraj do master branche"

Nas postup

Pro nas je dulezita jedna vec. Nikdy a za zadnych okolnosti by se nemelo nic delat primo do master branche. Takze vzdycky kdyz zacinate na necem pracovat, tak se v gitu musite prepnout do nove vetve, kterou pojmenujete jako feature/to-na-cem-pracujete. Kdyz si vytvorite novou branch, bacha na to, abyste se do ni zarovel taky prepnuli. Git ma prikaz jak jen na vytvoreni, a na vytvoreni a rovnou prepnuti do nove branche

Jak se teda vlastne delaji zmeny. Muzete na lokale upravovat soubory, ukladat je do lokalniho filesystemu, ale v tu chvili jeste nejsou ulozene v GITu. Kdyz je chcete ulozit do GITu, tak musite udelat tzv COMMIT. COMMITem rikate, ze "tohle jsou zmeny, ktere povazuji za definitivni a je to moje prace". V tortoiseGit je i mozne naklikat, ktere vsechny soubory chcete commitovat. Takze, az budete na necem delat, tak budete menit obsahsouboru, a pote co to udelate, tak to vsechno shrnete a ulozite do commitu.

Pri vytvareni noveho commitu je potreba zadat COMMIT MESSAGE. Vetsinou vyplnujeme jen prvni radek / message. Zcommit message by melo byt jasne, co se v tom commitu deje. Takze kdyz treba opravujete jak vypada menu na telefonech, tak by commit message mela vypadat jako "Oprava menu pod 400px:zapomenuta trida elementu". Akceptovatelne je "Oprava mobilniho menu", horsi je "oprava menu",a uplne nejhorsi commit message je "bugfix". Proste, vzdycky zkousejte byt co nejvic specificti, aby bylo jen podle toho jednoradkoveho popisu zrejme, co a jak se udelalo

Je mozne, ze pri posilani prvniho commitu se GIT zepta na jmeno a email, protoze GIT uklada krome zmen i jmeno a email autora, ktery zmeny delal. Pokud se na to zepta tortoise, tak vas hodi primo do dialogu kde to bude mozne vyplnit. Pokud pouzivate terminal, tak git vypise prikazy kterymi se da jmeno a email nastavit.

COMMIT obecne by mel splnovat par pravidel. Mel by obsahovat nejakou ucelenou jednotku prace. Kod pred commitem a po commitu by mel byt porad funkcni. Nemeli byste commitovat neco, co by tu aplikaco rozbilo. Samozrejme v prubehu praci ta aplikace rozbita bude, ale po commitu by mela byt alespon nejaka dilci jednotka hotova. Takze napriklad kdyz byste delali na funkci, ktera by implementovala kontaktni formular do webu, tak byste udelali novou branch feature/contact-form, do ktere byste postupne pridali commity "Kontaktni formular: HTML sablona kontaktniho formulare", "KF: odeslani formulare (PHP backend)", "KF: nastylovani formulare". To je jen priklad jak by to mohlo vypadat. Pravidlo je commitovat tak casto jak to jde. A je lepsi commitovat neco napul rozbiteho nez necommitovat vubec. Co je spatne je pracovat mesic na jedne funkci, a pak z toho udelat jeden obri commit. Nasi vyvojari maji treba 5-10 commitu za den kdyz na necem delaji, minimum by melo byt commitovat alespon jednou denne.

Ted co se stalo, tak po ulozeni COMMITU se tento ulozi do LOKALNI git repository na vasem pocitaci. Ale diky tomu, ze je GIT distribuovany system, (viz vyse), tak bitbucket (nebo obecne hlavni git server) o te nove zmene jeste nevi. Ale bitbucket je misto, odkud my se muzeme podivat na to co jste udelali. Takze ted potrebujeme udelat tu synchronizaci, a commity z lokalniho pocitace nahrat na server.

K tomu slouzi GIT prikaz PUSH. Zase, tortoise by mela mit moznost nekde v nabidce. Obvykly postup je takovy, ze prubezne budete delat commity, prubezne je pushovat. V okamziku, kdy budete spokojeni s tim co jste udelal a povazujete to za dokoncene, tak udelate tzv PULL REQUEST (nekdy uznacovany jako MERGE REQUEST). Tim rikate "Mam hotovo, a zadam o MERGE mych zmen do hlavni master branche". PULL REQUEST se dela z bitbucketu, u zobrazeni detailu branche je vpravo nahore odkaz "CREATE PULL REQUEST". Zde zpravidla staci potvrdit to co tam je, pokud jste davali rozumny nazev branche a slusne commit messages, tak to usnadnuje praci a staci jen potvrdit.

V tuhle chvili je to signal pro senior developera, pripadne zadavatele ukolu, ze je neco pripravene ke kontrole. Takze se na to podivame, diky gitu si to muzeme rozjet u sebe lokalne, overit funkcnost, a pripadne k tomu napsat nejake komentare. O komentarich z bitbucketu chodi notifikace emaiem, pripadne jsou videt i na detailu pull requestu v bitbucketu. Vzdycky je rovnou videt, k cemu presne (k jakemu radku) ten komentar patri.

Muze se stat, ze pull request schvalime bez namitek. Ale vetsinou se stava, ze budeme mit pripominky, at uz k funkcnosti, tak i ke stylu jakym je kod napsany (snazime se, aby kod od vsech lidi vypadal stejne). V takovem pripade je pak na vas tam ty zmeny zapracovat - podivate se co je potreba (tj. na konkretni komentar), zmenite kod, a udelate novy commit a push - vse stale do stejne branche.

Nakonec dojdeme k tomu, ze je kod schvaleny, my ho zmergujeme do master branche, a muzete se pustit do dalsich veci. K tomu je potreba posledni vec, to synchronizovat master vetev ve vasi lokalni git repository. K tomu slouzi prikaz PULL. Nejprve je nutne prepnout se zpet na vetev master, zde udelat git pull, a pote je jiz mozne vytvorit novou pracovni vetev a nasledovat postup popsany vyse.

Shrnuti

  1. pri zacatku prace je zakladem je mit git repository, a byt v master branchi (git checkout master) a stahnout si nejnovejsi verzi master branche ze serveru (git pull)
  2. vytvorit novou feature branch a prepnout se do ni git checkout -b feature/moje-nova-funkce
  3. prubezne delat zmeny / pridavat soubory a pote je commitovat. K pridani souboru do commitu slouzi prikazy git add cesta/k/souboru.html, a k ulozeni commitu pote git commit -m "Toto je git commit zprava ktera popisuje zmenu"
  4. nekteri GUI git klienti, jako napr. TortoiseGIT spojuji git add a git commit do jednoho prikazu, tj. ze git add neni treba volat separatne
  5. po commitovani je treba synchronizovat GIT na serveru, zpravidla staci git push. Specifictejsi priklad je git push origin feature/moje-nova-funkce - git push zustava, origin znaci na jaky vzdaleny GIT server se bude pushovat, a feature/moje-nova-funkce je nazev vetve pod kterou se push ulozi na vzdalenem serveru.
  6. po dokonceni prace a pushovani vseho je treba udelat v bitbucketu PULL REQUEST
  7. v pripade, ze dostanete ke kodu pripominky opakovat kroky 3-5. Pull request neni po kazdem push potreba vytvaret znova, bitbucket jej automaticky updatuje pokud pushujete do stejne vetve
  8. po schvaleni pripominek je funkce hotova, a muzete pokracovat na necem dalsim - zpet na krok 1., prepnete se v lokalni git repository na master git checkout master, synchronizujte si posledni zmeny z git serveru (git pull).
  9. ...