Java týden Java týden
Pouze tento týden sleva až 80 % na celý Java e-learning!
Brno? Vypsali jsme pro vás nové termíny školení OOP v Brně!

Lekce 3 - Dokončení kalkulačky v Angular frameworku

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, První aplikace v Angular frameworku, jsme započali tvorbu jednoduché kalkulačky ve frameworku Angular. V dnešním tutoriálu na ni navážeme a dokončíme ji. Minule jsme tedy skončili u služeb a dnes 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.com­ponent.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/calcu­lator/calcula­tor.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 } 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 {

  /** 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; // Převod operace na hodnotu číselníku.
    // Necháme si vypočítat výsledek podle zvolené operace a zadaných hodnot.
    this.result = this.calculatorService.calculate(Operation[operation], values.x, values.y);
  }
}

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.com­ponent.html

Začneme opět šablonou pro hlavní komponentu naší aplikace, kterou 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/calcu­lator/calcula­tor.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/calcu­lator/calcula­tor.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 velikost. 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. Příště začneme úplně novou pořádnou aplikaci v Angularu. A co to bude, to se nechte překvapit! ;)


 

Stáhnout

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

 

 

Článek pro vás napsal Jindřich Máca
Avatar
Jak se ti líbí článek?
2 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. :-)
Předchozí článek
První aplikace v Angular frameworku
Všechny články v sekci
Základy Angular frameworku
Aktivity (2)

 

 

Komentáře

Avatar
Ladislav Niderle:3. února 15:21

Mo cděkuji za tento tutoriál, hledal jsem něco podle čeho se dá naučit základ a zatím nenašel až zda, kde je zase základ vysvětlen, takže budu schopen potom i dále nasávat informace i z cizích zdrojů. Takže moc děkuji a těším se co všechno se zde naučím v tomto jazyce.

Myslíš, že by se dalo potom až budeš mít tento kurz hotový udělat jenom nějaký miniprojekt, kde se ukáže jak angularm tak i práce se serverem ať s php nebo javou a komunikace mezi nimi? Děkuji

 
Odpovědět 3. února 15:21
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Ladislav Niderle
Jindřich Máca:3. února 17:49

Ahoj, tak v první řadě jsem moc rád, že se seriál líbí. :)

Co se potom týče komunikace mezi serverem a klientem, tak je to předběžně v plánu už na další díly tohoto seriálu, ale kdy přesně vyjdou zatím nejsem schopen s jistotou říct.

 
Odpovědět  +1 3. února 17:49
Avatar
Odpovídá na Jindřich Máca
Ladislav Niderle:4. února 4:26

Tak to už se těším a nevadí, když se neví kdy to bude, ale hlavní pro mně je, že se s tím počítá a uvidím jak se taková aplikace správně tvoří od nuly.

 
Odpovědět 4. února 4:26
Avatar
David Tilšer:10. února 16:42

Ostatním to funguje? Mně to vrací chybu:
Uncaught Error: Template parse errors:
Can't bind to 'formGroup' since it isn't a known property of 'form'. ("<form [ERROR ->][formGroup]="cal­culatorForm" (ngSubmit)="on­Submit()">
<label for="x">
První číslo: <input id="x"): ng:///AppModu­le/Calculator­[email protected]:6
at syntaxError (compiler.js:2426)

Někdo řešil něco podobného?

Odpovědět 10. února 16:42
Odpočinek je pro slabochy.
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na David Tilšer
Jindřich Máca:11. února 20:37

Zdravím, importoval sis správně ReactiveFormsModule popsaný v předchozím díle? :)

 
Odpovědět 11. února 20:37
Avatar
Odpovídá na Jindřich Máca
David Tilšer:11. února 22:22

Děkuji, opravdu mi tam ten import chyběl. Už to jede tak jak má :-)

Odpovědět  +1 11. února 22:22
Odpočinek je pro slabochy.
Avatar
Václav Čížek:2. dubna 14:28

Ahoj Jindřichu, díky za fajn tutoriál! :) Chci se zeptat na pár nesrovnalostí. Založil jsem novou aplikaci pomocí pžíkazu "ng new calculator", vstoupil do vytvořené složky a spustil příkazem "ng serve --open" a otestoval v prohlížeči na adrese http://localhost:4200/, že nová aplikace běží. Potom jsem postupoval krok za krokem podle tvého návodu. Na konci ale prohlížeč nic nezobrazoval, ale snažil se něco načíst, neúspěšně. Po vypnutí služby jsem spustil příkaz "npm install", aplikace začala fungovat. Netušíš, čím by to mohlo být způsobeno?
Druhá věc je, že když v kalkulačce provádím např. operaci 8,2 - 0,2, dostanu výsledek 7.999999999999999. Čím by to mohlo být a jak by se to dalo ošetřit? Předem děkuji za odpověď

 
Odpovědět 2. dubna 14:28
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Václav Čížek
Jindřich Máca:2. dubna 15:31

Ahoj, v první řadě není zač, jsem rád, že se tutoriál líbí. :)

Potom k těm problémům:

  1. Příkaz npm install nainstaluje všechny knihovny závislostí. Je možné, že tam něco chybělo. Přímo na konci tohoto článku je o tom napsané varování. ;)
  2. Problém s aritmetikou není vůbec problém Angularu, ale čistého JavaScriptu. Když se v JS napíše stejný výpočet, dostaneš stejný výsledek. :) No pak, když už víš co hledáš, tak např. jeden z prvních výsledků z Googlu - https://www.avioconsulting.com/…ision-issues, ale věřím, že tady už si poradíš.
 
Odpovědět 2. dubna 15:31
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 8 zpráv z 8.