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/calculator.service.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/controllers/calculator.controller.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 92x (15.24 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript