Úvod do AngularJS

JavaScript AngularJS Úvod do AngularJS

Nástupem technologií HTML5 se JavaScript nebývale rozrostl. Aplikace v tomto jazyce se stávají čím dál víc komplexní a samotná knihovna jQuery na to přestává stačit. Má totiž jednu velkou nevýhodu a to, že míchá dohromady aplikační logiku, zpracování událostí a manipulaci s DOM. U menších aplikací, webových stránek či widgetů to zase takový problém není. Problém nastává, pokud se daná aplikace či widget rozroste natolik, že se programátor začne v kódu ztrácet. V takovém případě nastupuje na řadu architektura MVC nebo nějaký její derivát.

Když jsme se tedy rozhodli používat MVC architekturu, narazíme na pár problémů. Jak ji implementovat v JavaScriptu a jak udělat template systém? HTML je dobré pro deklaraci statických dokumentů, ale co když potřebujeme vytvořit dynamické aplikace, kde se informace ve View (tedy v HTML) neustále mění? AngularJS je MVC framework od Googlu, který rozšiřuje HTML o řadu elementů a atributů, díky kterým je vytvořit takový dynamický HTML dokument hračka. Navíc umožňuje vytvářet vaše vlastní HTML elementy a atributy, obsahuje two-way data binding a má spoustu dalších užitečných vlastností díky nimž se kód stává extrémně přehledný, jednoduchý a krátký.

Nejlepší bude, předvést tento framework na konkrétním příkladu. Vytvoříme si tabulku, do které budeme moci přidávat záznamy, řadit je a vyhledávat mezi nimi. Pro pouhý javascript nebo i jQuery je tento úkol těžší, než se na první pohled zdá. Pro AngularJS je to však hračka.

Vytvoříme si tedy základní HTML dokument.

<!DOCTYPE html>
<html ng-app>
    <head>
        <meta charset="UTF-8" />
        <title>Úvod do AngularJS | devbook.cz</title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
        <script type="text/javascript" src="js/controllers.js"></script>
    </head>
    <body ng-controller="FrameworksController">
        <section>
            <header>
                <h1>Seznam framework&#249;</h1>
                <input type="text" placeholder="hledaný výraz" id="search" ng-model="searchQuery" />
            </header>

            <table>
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Jméno</th>
                        <th>Popis</th>
                        <th>Jazyk</th>
                    </tr>
                </thead>
                <tbody>
                    <tr ng-repeat="fw in frameworks | filter:searchQuery ">
                        <td>{{fw.id}}</td>
                        <td><a ng-href="{{fw.link}}">{{fw.name}}</a></td>
                        <td>{{fw.description}}</td>
                        <td>{{fw.language}}</td>
                    </tr>
                </tbody>
            </table>
        </section>
    </body>
</html>

Na první pohled klasický HTML dokument, ale některé elementy obsahují speciální atributy (direktivy), které do klasického HTML nepatří. Tyto direktivy zpracovává Angular.

ngApp

Tato direktiva automaicky spustí naši aplikaci. Jako parametr očekává název hlavního modulu aplikace. My parametr zatím vynecháme.

ngModel

Je direktiva, která říká Angularu, aby použil two-way data binding. Veškeré změny ve scope se promítnou na tomto elementu a naopak, veškeré změny hodnoty vázaného elementu se projeví ve scope. Funguje pouze s elementy input, select a textarea

{{ AngularJS výraz }}

Výraz mezi dvěma složenými závorkami také zpracovává AngularJS. Syntaxe je stejná jako syntaxe JavaScriptu. Můžete zde vypisovat hodnoty pole, objektu, proměnné, volat funkce a používat tzv. filtry. Filtry se zapisují za znak '|' a mají syntaxi | jméno_filtru:argument1:argument2. O filtrech si povíme víc příště.

ngRepeat

Je cyklus, který projde pole a pro každou iteraci zopakuje prvek, ke kterému se váže (v našem případě celý element tr). Vytváří uvnitř elementu speciální proměnné. Jednak proměnnou obsahující aktuální položku pole (fw) a pak speciální proměnné $index, která obsahuje aktuální index položky, $first je logická hodnota (true, pokud je položka první v poli), $middle opět logická hodnota (true pokud je položka mezi prvním a posledním prvkem) a $last. Všiměte si, že všechny proměnné, které přidal angular, začínají znakem dolaru. Je to tak proto, aby nevznikl konflikt mezi proměnnými přidanými námi a proměnnými angularu. Výsledek ngRepeat se dá filtrovat a řadit. Toho docílíme speciálním filterm filter. Jako argument očekává text, podle kterého bude pole filtrovat. My mu předáme proměnnou searchQuery.

ngController

Předá danému elementu scope controlleru, kterého mu předáme parametrem. Tedy pouze jméno controlleru.

Model a Controller

V AngularJS je modelem jakýkoli objekt předaný do scope. V našem případě to bude jen pole objektů s danými informacemi. Vytvoříme ho v controlleru na objektu $scope, který controlleru předáme (resp. AngularJS předá) parametrem. Samotný controller bude představovat JS funkce.

function FrameworksController( $scope ) {
    $scope.frameworks = [{
        "id" : 1,
        "name" : "AngularJS",
        "link" : "http://www.angularjs.org",
        "description" : "HTML enhanced for web apps!",
        "language" : "javascript"
    },
    {
        "id" : 2,
        "name" : "jQuery",
        "link" : "http://www.jquery.com",
        "description" : "Write less, do more",
        "language" : "javascript"
    },
    {
        "id" : 3,
        "name" : "RaphaelJS",
        "link" : "http://www.raphaeljs.com",
        "description" : "Kreslete vektorovou grafiku javascriptem",
        "language" : "javascript"
    }];
};

I když controller sám zatím nic moc nedělá, plní tu důležitou roli. Poskytuje prostor, kam můžeme uložit informace, tedy scope. Každý scope v controlleru je potomkem root scope (tedy kořenového scope). Scope je velmi důležitý. AngularJS ho používá, aby oddělil model, controller a view ale zároveň je udržoval synchronizované. Změní-li se scope v data modelu, promítnou se změny v šabloně a obráceně, změní-li se scope v šabloně, změní se také i v data modelu (viz. obrázky pod tímto odstavcem). Toto je velmi užitečná vlastnost Angularu díky které máme vždy k dispozici aktuální informace.

One-way data binding

One-way data binding

Two-way data binding v AngularJS

Two-way data binding v AngularJS

Zpracování formuláře

Když už máme tabulku našich oblíbených frameworků, bylo by dobré, abychom je mohli dál přidávat. Vytvoříme proto formulář.

<form ng-submit="addFramework()">
    <input type="text" ng-model="data.name" placeholder="Jméno frameworku" />
    <input type="text" ng-model="data.link"  placeholder="Odkaz na web" />
    <select ng-model="data.language">
        <option value="" disabled="disabled">Programovací jazyk ...</option>
        <option value="javascript">JavaScript</option>
        <option value="java">Java</option>
        <option value="c#">C#</option>
        <option value="php">PHP</option>
        <option value="python">Python</option>
    </select>
    <textarea placeholder="Krátký popis" ng-model="data.description"></textarea>
    <input type="submit" value="P&#248;idat" />
</form>

I v tomto formuláři se objevily nám ještě neznáme atributy. Direktivu ngModel už známe. Jen bych podotknul, že pokud proměnná uvedené v ngModel neexistuje, Angular ji sám v daném scope vytvoří. Data z našeho fomuláře budeme ukládat do objektu data.

ngSubmit

Tato direktiva zpracovává javascriptovou událost onSubmit. V parametru je AngularJS výraz. Můžeme zde tedy nastavit hodnotu proměnným nebo spouštět funkce v našem scope. Stejně lze použít i direktivy ngClick, ngMouseover atp. V podstatě všechny základní JS události.

Poznámka: V aktuální verzi AngularJS (1.0.1) ještě neexistuje direktiva ngFocus a ngBlur. Ty budou přidány do verze 1.2 (viz. AngularJS 1.0 -> 1.2 Roadmap)

Musíme ještě vytvořit odpovídající metodu addFramework v našem controlleru FrameworksController. Tato metoda přidá objekt data do našeho pole a vynuluje ho. Tak zmizí i data v našem formuláři a přidá se nový záznam do tabulky.

$scope.addFramework = function() {
    // Přiřadíme záznamu číslo ID
    $scope.data.id = $scope.frameworks.length+1;
    // Vložíme objekt data do pole frameworků
    $scope.frameworks.push($scope.data);
    // a vynulujeme ho
    $scope.data = {};
};

Nyní už můžeme přidávat nové záznami přes tento formulář. Nicméně tohle je pouze základní práce s formuláři v AngularJS. Pokročilejší manipulace s nimi jako jsou různé validace atp. si ukážeme někdy jindy.

Sledování změn ve scope

Někdy je třeba sledovat změny objektů ve scope a podle toho rozhodnout, co se bude dít. Scope má na takové případy speciální metodu $watch. V parametrech tato funkce chce název hodnoty, kterou sledujeme, funkci, která se vykoná při každé změně a jestli má porovnávat objekty.

V naší aplikaci by bylo dobré ukládat frameworky do nějakého uložiště, aby se nám náš seznam nesmazal po každém obnovení stránky. K tomu můžeme použít třeba localStorage. Abychom tak nepřišli o naše záznamy v tabulce, vytvoříme si watcher v našem controlleru sledující pole frameworků a při každé jeho změně uložíme novou hodnotu do localStorage.

$scope.$watch(
    // Budeme sledovat změny v ojektu frameworks
    'frameworks',
    // Funkce má v parametrech aktuální a starý seznam frameworků
    function( newList, oldList ) {
        // a uložíme je do lokálního uložiště jako
        localStorage.setItem('frameworks', JSON.stringify(newList));
    },
    // Porovnáváme dva objekty
    true
);

Teď se nám informace ukládají na lokální uložiště, tak by bylo dobré je odtamtud při každém načtení aplikace vytáhnout. Jednoduše nastavíme v controlleru $scope.frameworks = JSON.parse(localStorage.getItem('frameworks')) || [];

Řazení ngRepeat a dokončení aplikace

Už jsme skoro u konce. Nyní si zkusíme jen seřadit tabulku po kliknutí na záhlaví daného sloupce. V ngRepeat můžeme kromě filtru filter použt i filtr orderBy, který seřadí pole podle zadaných hodnot. Ty jsou dvě, jednak jméno vlastnosti, podle které chceme pole sešadit (např. name, id, description atd. - odpovídá klíčům objektu) a pak jestli má pole seřadit vzestupně nebo sestupně (logická hodnota - není povinná). Přidáme tedy tento filter k výrazu direktivy ngRepeat: ng-repeat="fw in frameworks | filter:searchQuery | orderBy:orderProp:reverse". Tak seřadíme pole vždy podle hodnoty proměnné orderProp a reverse. Pokud nebudou definovány v našem scope, nebude pole seřazeno, takže je ani definovat nemusíme. Nicméně pokud byste chtěli mít pole seřazeno, stačí vytvořit v scope dané proměnné.

Teď jen nastavit proměnné orderProp a reverse po kliknutí na záhlaví každého sloupce naší tabulky. Na to použijeme direktivu ngClick, která se chová stejně jako již zmíněná direktiva ngSubmit, akorát zpracovává jinou událost (onClick). Změníme záhlaví naší tabulky.

<thead>
    <tr>
        <th ng-click="orderProp = 'id'; reverse = !reverse;">ID</th>
        <th ng-click="orderProp = 'name'; reverse = !reverse;">Jméno</th>
        <th ng-click="orderProp = 'description'; reverse = !reverse;">Popis</th>
        <th ng-click="orderProp = 'language'; reverse = !reverse;">Jazyk</th>
    </tr>
</thead>

Tak a máme hotovo. Máme funkční tabulku, která jde řadit, lze v ní vyhledávat a dokonce i přidávat záznamy, aniž by se smazali po obnovení stránky. Nakonec k článku přikládám ke stažení zdrojové kódy aplikace. Zajímavé na této aplikaci je fakt, že CSS styly jsou několikrát větší než HTML struktura a kód controlleru dohromady. Více se o AngularJS dozvíte na oficiálních stránách AngularJS.org.


 

Stáhnout

Staženo 1406x (3.94 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

  Aktivity (1)

Článek pro vás napsal Drahomír Hanák
Avatar
Autor v současné době studuje Informatiku. Zajímá se o programování, matematiku a grafiku.

Jak se ti líbí článek?
Celkem (13 hlasů) :
55555


 


Miniatura
Všechny články v sekci
AngularJS
Miniatura
Následující článek
AngularJS filtry&moduly

 

 

Komentáře
Zobrazit starší komentáře (16)

Avatar
Drahomír Hanák
Tým ITnetwork
Avatar
Drahomír Hanák:

Můžeš si uložit referenci na funkci do nějaké proměnné a předat filtru orderBy tu proměnnou.

// kontroller
$scope.razeni = angular.noop;
$scope.seraditPodle = function(funkce) {
    $scope.razeni = funkce == null ? angular.noop : funkce;
};
$scope.abecedniRazeni = function(prvek) { return String(prvek); };

// šablona
<button ng-click="seraditPodle(abecedniRazeni)">řadit podle abecedy</button>
<ul>
  <li ng-repeat="meal in myMeal | orderBy:razeni">...</li>
</ul>

angular.noop je funkce, která nic neudělá (angular.noop = function(){};)

 
Odpovědět 4.7.2014 10:09
Avatar
roman.kratochvil:

Uvedený příklad nefunguje v IE ani v Edge, funguje v Chrome....

 
Odpovědět 26. října 15:42
Avatar
roman.kratochvil:

Nefunguje ten grid (ten seznam), vypadá to, že to je kolem ng-repeat....

Chci sem vložit screeny, ale nevím jak, dole dám vybrat soubory a nic.....

Editováno 27. října 8:49
 
Odpovědět 27. října 8:46
Avatar
Odpovědět 27. října 9:06
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
roman.kratochvil:

v png jsme to dělal, teď to je v jpg!

Díky za trknutí

Editováno 27. října 9:32
 
Odpovědět 27. října 9:31
Avatar
Odpovídá na Marian Benčat
roman.kratochvil:

Tady jsou screeny

Jsem myslel, že to je multiplatformní, ale zase chrome vs. IE....

 
Odpovědět 27. října 9:34
Avatar
Marian Benčat
Redaktor
Avatar
Odpovídá na roman.kratochvil
Marian Benčat:

Je to multi platformni.. Nejaka chyba v konzoli?? Vsadil bych boty na neco ve stylu ze indexOf() je undefined :-)

Pouzivaji to skoro vsechny knihovny, ale IE asi az do 10tky to v zákaldu nemá a dává se na to polyfill.

 
Odpovědět 27. října 10:16
Avatar
Odpovídá na Marian Benčat
roman.kratochvil:

V Edgi to nefunguje taky.
Chrome je jedinej kde to funguje.

 
Odpovědět 27. října 10:49
Avatar
Odpovídá na Marian Benčat
roman.kratochvil:

Tak už to funguje :-) Otevřel jsem si to ve VS2015 jako website a tam jsem si to spoustil funguje to. Předtím jsme to spouštěl klasicky přes souborový systém (to funguje jenom v chromu).
Je to divné, ale výsledné aplikace fungují stejně přes IIS tak to nebudu řešit.

 
Odpovědět 27. října 11:08
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 26. Zobrazit vše