Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 4 - Dokončení kalkulačky v AngularJS

V minulé lekci, První aplikace v AngularJS, jsme dokončili aplikační strukturu a stáhli si potřebné knihovny pro naši aplikaci.

Dnes se budeme zabývat modelem, kontrolerem a šablonou, takže bez dalšího otálení jdeme na to! :)

Model

Naši kalkulačku začneme implementovat od jejího modelu tj. od jejích služeb v podání AngularJS.

app/services/cal­culator.servi­ce.js

Řekněme, že naše kalkulačka bude mít 4 základní operace, tj. sčítání, odčítání, násobení a dělení. Tyto operace umístíme do modelu, protože nám vracejí výsledky, tj. naše data. Do souboru calculator.service.js tedy doplníme AngularJS službu, která plní onu roli modelu a vypadá následovně:

'use strict';

/**
 * Model operací kalkulačky.
 */
app.service('Calculator', function () {
    /**
     * Sečte daná čísla a vrátí výsledek.
     * @param {int} x první číslo
     * @param {int} y druhé číslo
     * @return {int} výsledek sčítání
     */
    this.add = function (x, y) {
        return x + y;
    };

    /**
     * Odečte druhé číslo od prvního a vrátí výsledek.
     * @param {int} x první číslo
     * @param {int} y druhé číslo
     * @return {int} výsledek odčítání
     */
    this.subtract = function (x, y) {
        return x - y;
    };

    /**
     * Vynásobí daná čísla a vrátí výsledek.
     * @param {int} x první číslo
     * @param {int} y druhé číslo
     * @return {int} výsledek násobení
     */
    this.multiply = function multiply(x, y) {
        return x * y;
    };

    /**
     * Vydělí první číslo druhým bezezbytku a vrátí výsledek.
     * @param {int} x první číslo
     * @param {int} y druhé číslo
     * @return {int} výsledek dělení beze zbytku
     */
    this.divide = function (x, y) {
        return Math.round(x / y);
    };
});

Kromě definice služby ve frameworku by zde pro vás nemělo být nic překvapivého. Můžete si ale povšimnout, že jelikož jsem se rozhodl provádět operace v celých číslech, tak chci tuto vlastnost zachovat i u dělení, tudíž výsledek zaokrouhluji na celá čísla. Dále si bystřejší z vás určitě všimli, že není ošetřeno dělení nulou. To však technicky není chyba, protože pro JS toto nekončí chybou, ale číselnou hodnotou "nekonečno" :)

Takže základní operace bychom měli, to však ještě není všechno. Jelikož by model měl být rozšiřitelný a podle MVC bychom při změně modelu nejlépe neměli měnit ani kontroler, ani šablonu, přidáme si ještě jednoduché rozhraní, které nám tyto vlastnosti zajistí. To znamená, že přidáme ještě následující vlastnost a metodu:

...
/**
 * Definice pole konstant pro operace kalkulačky.
 * @type {String[]}
 */
Object.defineProperty(this, 'operations', {
    value: {
        add: 'Sčítání',
        subtract: 'Odčítání',
        multiply: 'Násobení',
        divide: 'Dělení beze zbytku'
    },
    enumerable: true
});
...
/**
 * Zavolá zadanou operaci a vrátí její výsledek.
 * @param {string} operation zadaná operace
 * @param {int} x            první číslo pro operaci
 * @param {int} y            druhé číslo pro operaci
 * @return {int|null} výsledek operace nebo null, pokud zadaná operace neexistuje
 */
this.calculate = function (operation, x, y) {
    if (this.hasOwnProperty(operation))
        return this[operation](x, y);
    else return null;
}
...

První část kódu definuje novou vlastnost operations, která obsahuje názvy operací a jejich popisky. Druhá část kódu definuje metodu, která podle textového řetězce s názvem operace zavolá danou metodu kalkulačky. Protože název operace bude shodný s názvem metody, můžeme podle něj metodu vybrat jako this[operation], kdy v operation je např. hodnota "add", což spustí metodu add(). Opět nic, co vás při znalosti JS překvapí. Kdo náhodou neví, tak takto se v JS definují objektové vlastnosti a provádí reflexe :)

Kontroler

Pokračovat budeme implementací kontroleru v rámci AngularJS.

app/controller­s/calculator.con­troller.js

Vytvoříme jej tedy v souboru calculator.controller.js a vypadat bude následovně:

'use strict';

/**
 * Kontroler kalkulačky.
 * @param {Object} Calculator model operací kalkulačky předaný pomocí DI
 */
app.controller('CalculatorController', function (Calculator) {
    // Počáteční nastavení hodnot.
    this.x = 0; // První číslo.
    this.y = 0; // Druhé číslo.
    this.operations = Calculator.operations; // Předání výběru operací kalkulačky.
    this.operation = Object.keys(this.operations)[0]; // Výchozí operace kalkulačky (první v seznamu.)
    this.result = null; // Výsledek výpočtu.
    // Definice metod.
    /**
     * Metoda vykonaná při odeslání formuláře kalkulačky, která zpracuje odeslané hodnoty.
     */
    this.calculate = function () {
        this.result = Calculator.calculate(this.operation, this.x, this.y);
    };
});

Zde bych se již na chvíli zastavil. Nejdříve si povšimněte definice kontroleru v rámci frameworku, kde je také vidět DI (Dependency Injection, která nám umožňuje předávat služby napříč naší aplikací). Ta v AngularJS funguje opravdu skvěle, když v kontroleru potřebujeme používat nějaký model, jednoduše si jej necháme frameworkem předat. Stačí napsat název služby jako parametr a je hotovo, žádná další konfigurace není třeba.

Dále se zde definují proměnné, které budou fungovat v šabloně pro předání hodnot. Pokud tedy deklarujeme proměnnou lokálně, bude k dispozici pouze pro kontroler jako takový. Pokud ji ale uděláme přímo na objektu, bude dostupná i v šabloně. To samé platí i u metod, které poté můžeme volat jako akce z šablon.

U proměnných tento princip navíc ještě znamená, že díky obousměrnému bindování (propisování hodnot mezi HTML šablonou a JS proměnnými), což je jedna z hlavním předností AngularJS frameworku, zde vlastně definujeme počáteční hodnoty v šabloně. Ostatně to za chvíli uvidíte :)

Šablona (View)

Na závěr si doplníme šablonu pro náš kontroler, což je vlastně mix hlavně HTML a AngularJS kódu.

index.html

Šablonu pro jednoduchost vepíšeme přímo do souboru index.html a to dovnitř připraveného "wrapperu". Ovšem nutno podotknout, že standardně bývají šablony odděleny v souborech zvlášť.

...
<!-- HTML + AngularJS kód aplikace, především pak formulář kalkulačky. -->
<div id="wrapper" ng-controller="CalculatorController as calculator">
    <h1>Kalkulačka v AngularJS</h1>
    <form ng-submit="calculator.calculate()">
        <label for="x">
            První číslo:
            <input id="x" type="number" required ng-model="calculator.x">
        </label>
        <label for="y">
            Druhé číslo:
            <input id="y" type="number" required ng-model="calculator.y">
        </label>
        <label for="operation">
            Operace:
            <select id="operation" required ng-model="calculator.operation"
                    ng-options="key as value for (key , value) in calculator.operations">
            </select>
        </label>
        <input type="submit" value="Spočítej">
    </form>
    <div id="result" ng-cloak ng-show="calculator.result">Výsledek je: {{calculator.result}}</div>
</div>
...

Na závěr si pojďme tento kód trochu rozebrat. Jeho základ tvoří HTML formulář, to by mělo být jasné. Dále je vidět definice kontroleru pomocí ng-controller, která v podstatě říká, že tento blok HTML kódu se mapuje jako jeho šablona a má tím pádem přístup k jeho datům a akcím. Zároveň je zde pro něj zaveden alias "calculator".

Posléze se tedy mapuje odeslání formuláře (submit) na akci kontroleru "calculate" pomocí ng-submit a jednotlivé proměnné tohoto kontroleru jako model pro formulář pomocí ng-model. Tím se prováže předávání dat pomocí již zmíněného bindování.

Další věcí je generování možností pro HTML <select> pomocí ng-options, které je vytváří přímo z předaných hodnot kontroleru.

Na konci je poté vidět zobrazení výsledku pomocí frameworkového zápisu {{...}}, pokud je definován (ng-show), který se díky Angularu dynamicky mění v závislosti na aktuálním výpočtu. Důležité je zde také označení ng-cloak, které daný element schová pomocí CSS, dokud není JS načtený, aby mohl převzít kontrolu. Toto CSS jsme si definovali už v minulé lekci.

A tím je naše práce na šabloně i na celém projektu hotová. Pokud se teď podíváte na URL projektu, měli by jste vidět funkční kalkulačku a můžete na ní vyzkoušet všechny chytáky, které vás napadnou :)

Pokud vám není cokoli jasné, stáhněte si projekt z přílohy a projeďte si ho. Kódu v aplikaci tolik nemáme, po chvíli byste se v principu měli zorientovat.

To je pro tuto lekci opravdu vše.

V další lekci, Jednoduchý redakční systém v AngularJS - Struktura projektu, si připravíme projektovou strukturu pro jednoduchý redakční systém :)


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

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

 

Předchozí článek
První aplikace v AngularJS
Všechny články v sekci
AngularJS
Přeskočit článek
(nedoporučujeme)
Jednoduchý redakční systém v AngularJS - Struktura projektu
Článek pro vás napsal Jindřich Máca
Avatar
Uživatelské hodnocení:
1 hlasů
Autor se věnuje převážně webovým technologiím, ale má velkou zálibu ve všem vědeckém, nejen ze světa IT. :-)
Aktivity