Lekce 3 - Dokončení kalkulačky v Angular frameworku
V minulé lekci, První aplikace v Angular frameworku, jsme započali tvorbu jednoduché kalkulačky ve frameworku Angular.
V dnešním tutoriálu se budeme zabývat především komponentami. Naposled
jsme skončili u služeb a tak na ně navážeme Angular komponentami, takže
bez dalšího otálení jdeme na to!
Komponenty
V rámci zachování nějaké struktury si rozdělíme práci s komponentami na definice jejich tříd, jejich šablony a samozřejmě styly v podobě CSS.
Definice
Začneme tedy implementací tříd komponent v TypeScriptu.
src/app/app.component.ts
Ze všeho nejdříve se opět podíváme na zoubek hlavní komponentě celé naší aplikace, kde je mimo jiné definován hlavní nadpis naší stránky:
import { Component } from '@angular/core'; /** * Hlavní komponenta celé aplikace. * @export */ @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'Kalkulačka v Angular frameworku'; }
Zde už bylo vše potřebné řečeno v předchozích lekcích.
Pokračovat budeme implementací komponenty pro naši kalkulačku v rámci Angularu. Opět můžeme využít Angular CLI a nechat si základ komponenty vygenerovat jediným příkazem:
ng generate component calculator
src/app/calculator/calculator.component.ts
Jak jste si mohli všimnout např. v předešlé lekci na obrázku, základem naší aplikace je webový formulář pro kalkulačku. A právě tato komponenta bude mít na starost tvorbu a obsluhu tohoto formuláře spolu s využitím služby pro výpočty, kterou jsme minule definovali. Pojďme tedy vytvořit definici našeho formuláře do naší komponenty:
import { Component, OnInit } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; import { CalculatorService } from '../services/calculator.service'; import { Operation } from '../services/operation'; /** * Komponenta kalkulačky. * @export */ @Component({ selector: 'app-calculator', templateUrl: './calculator.component.html', styleUrls: ['./calculator.component.css'] }) export class CalculatorComponent implements OnInit { /** Výsledek operace nebo null. */ result: number | null = null; /** Formulář kalkulačky s jeho sestavením. */ calculatorForm = this.formBuilder.group({ x: [0, Validators.required], y: [0, Validators.required], operation: ['', Validators.required] }); /** * Konstruktor s injektovanou službou pro sestavování formulářů a pro práci s operacemi kalkulačky. * @param formBuilder automaticky injektovaná služba pro sestavování formulářů * @param calculatorService automaticky injektovaná služba pro práci s operacemi kalkulačky */ constructor(private formBuilder: FormBuilder, private calculatorService: CalculatorService) { } /** Getter pro existující operace kalkulačky. */ get operations() { return Operation; } /** Funkce vykonaná při úspěšném odeslání formuláře kalkulačky, která zpracuje odeslané hodnoty. */ onSubmit(): void { const values = this.calculatorForm.value; // Získání odeslaných hodnot z formuláře. const operation: keyof typeof Operation = values.operation as keyof typeof Operation; // Necháme si vypočítat výsledek podle zvolené operace a zadaných hodnot. // Funkce calculate() očekává hodnoty x a y typu number. Hodnoty x a y tedy převedeme pomocí funkce Number(). this.result = this.calculatorService.calculate(Operation[operation], Number(values.x), Number(values.y)); } ngOnInit(): void { } }
Zde bych se již na chvíli zastavil. Nejdříve si povšimněte konstruktoru třídy, kde se aplikuje princip Dependency Injection (DI), která nám umožňuje předávat služby napříč naší aplikací. Ta v Angularu funguje opravdu skvěle, když v komponentě potřebujeme používat nějakou službu, jednoduše si jí necháme frameworkem předat. Stačí ji definovat jako parametr v rámci konstruktoru a je hotovo.
Dále se zde definují atributy, které budou zároveň fungovat v šabloně
komponenty. To samé platí i u metod, které poté můžeme volat jako akce ze
šablon. Pokud tedy opět jednoduše definujeme veřejný atribut třídy, bude
dostupný jako proměnná i v šabloně a zároveň spolu budou provázány -
při změně jednoho dojde ke změně i u druhého. Ostatně to za chvíli
uvidíte sami
Takže tedy jako atributy zde definují výsledek operace
result
, který budeme zobrazovat a dále pak samotný formulář
calculatorForm
. Ten je zde sestavován pomocí speciální služby,
která souvisí s modulem pro reaktivní formuláře z minulé lekce. Pomocí
ní jsou definovány jednotlivá pole formuláře i se svými validačními
pravidly. Dále je zde ještě getter operations()
, který vrací
seznam všech dostupných operací. Zpracování formuláře pak řeší
samostatná metoda onSubmit()
, kterou budeme volat při jeho
odeslání a je detailně zdokumentována již v kódu
V Angularu obecně existují hned dva nezávislé způsoby, jak
pracovat s webovými formuláři - reaktivní a šablonovací.
K tomu se ještě dají u obou řešit různé věci trochu jinými způsoby,
takže celkově by se tento formulář dal napsat více než dvěma naprosto
validními alternativami Dále
v kurzu si je ukážeme.
Šablony
Pokračovat budeme doplněním implementace šablon pro naše komponenty, což je vlastně mix hlavně HTML a Angular kódu.
src/app/app.component.html
Začneme opět šablonou pro hlavní komponentu naší aplikace. Obsah této šablony vymažeme a upravíme následovně:
<div style="text-align: center;"> <h1>{{ title }}</h1> <app-calculator></app-calculator> </div>
Vidíte, že zde pouze pozměníme titulek a místo obsahu vložíme naši komponentu kalkulačky. Nic víc zde není potřeba.
src/app/calculator/calculator.component.html
Dále budeme pokračovat se šablonou naší komponenty pro kalkulačku:
<form [formGroup]="calculatorForm" (ngSubmit)="onSubmit()"> <label for="x"> První číslo: <input id="x" type="number" required formControlName="x"> </label> <label for="y"> Druhé číslo: <input id="y" type="number" required formControlName="y"> </label> <label for="operation"> Operace: <select id="operation" required formControlName="operation"> <option value="">--Vyberte operaci--</option> <option *ngFor="let operation of operations | keyvalue" [value]="operation.key">{{ operation.value }}</option> </select> </label> <input type="submit" [disabled]="!calculatorForm.valid" value="Spočítej"> </form> <div id="result" [hidden]="result == null">Výsledek je: {{ result }}</div>
Pojďme si tento kód zas trochu rozebrat. Jeho základ tvoří HTML
formulář, to by mělo být jasné. Ten je provázaný na formulář
definovaný v naší komponentě pomocí direktivy formGroup
, díky
které pak máme přístup k jeho polím. Ty jsou potom svázány s jejich HTML
definicí pomocí formControlName
.
Následně je zde vidět také mapování odeslání formuláře
(ngSubmit)
na metodu naší komponenty onSubmit()
.
Další věcí je generování možností pro HTML
<select>
pomocí *ngFor
, které je vytváří
přímo z předaných hodnot komponenty.
Za zmínku také stojí dynamická validace formuláře na tlačítku pro jeho odeslání, která ho znepřístupní v případě, že je formulář nevalidní.
Na konci je poté vidět zobrazení výsledku pomocí standardního
frameworkového zápisu {{ ... }}
. Výsledek bude vidět, pouze
pokud je result
jiný než null
. Ten se díky Angularu
dynamicky mění v závislosti na aktuálním výpočtu.
Styly
Tímto je práce na šablonách hotova, ale my si ještě na závěr doplňme CSS k našim komponentám, aby alespoň trochu vypadaly.
src/app/calculator/calculator.component.css
Zde bude stačit styl k naší komponentě kalkulačky, protože u hlavní komponenty není v podstatě co stylizovat:
:host { display: flex; flex-direction: column; align-items: center; } label { display: block; clear: both; margin: 10px 0; } label > input { float: right; margin-left: 5px; } input[type="submit"] { display: block; margin: 0 auto; } #result { font-size: 1.5em; font-weight: bold; margin: 10px 0; }
O CSS v Angularu je zde třeba říct dvě věci. Za prvé, všechny styly
jsou izolované v rámci jednotlivých komponent. Tzn. že
zdejší styl pro label
nijak neovlivní tento element uvnitř
jiných komponent.
A druhá věc, pokud chceme naopak ovlivňovat alespoň částečně okolní
CSS, musíme použít speciální angularovské notace jako
např. uvedený :host
. Ten zařídí, aby naše komponenta jako
taková tj. <app-calculator>
, měla nějaký výchozí
styl.
A tím je naše práce na celém projektu dokončena. Pokud se teď
podíváte na příslušnou URL, měli byste 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.
V příloze nejsou nainstalované moduly, kvůli jejich
velikosti. Je tedy potřeba před spuštěním aplikace použít příkaz
npm install
.
To je pro tuto lekci opravdu vše.
V další lekci, Databázový klient v Angular - Příprava projektu, si připravíme adresářovou strukturu projektu, stáhnem hotový kód serveru a šablonu Angular klienta.
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 245x (214.53 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript