Trudny / egzaminacyjny · lekcja 11
Angular III — formularze reaktywne, walidacja i routing SPA
Ostatni element układanki Angulara: prawdziwe formularze z walidacją (nie tylko proste [(ngModel)] z lekcji 10) oraz nawigacja między "stronami" aplikacji jednostronicowej (SPA) — bez przeładowania całej strony w przeglądarce. Po tej lekcji będziesz mieć kompl...
Zacznij tutaj
Po co się tego uczymy?
Wprowadzenie
Teoria
Dwa podejścia do formularzy w Angularze. [(ngModel)] z lekcji 10 (tzw. "formularze szablonowe") sprawdza się w prostych przypadkach, ale profesjonalne, większe formularze buduje się przez Reactive Forms — podejście, gdzie CAŁA struktura formularza (pola, reguły walidacji) jest zdefiniowana w KODZIE TypeScript, a szablon HTML tylko się do niej "podłącza". To podejście jest bardziej przewidywalne i łatwiejsze do testowania w większych aplikacjach.
Budowa formularza reaktywnego. Klasa FormGroup reprezentuje CAŁY formularz, a FormControl — POJEDYNCZE pole, z opcjonalną wartością początkową i tablicą walidatorów:
import { FormGroup, FormControl, Validators } from '@angular/forms';
formularz = new FormGroup({
nazwa: new FormControl('', [Validators.required, Validators.minLength(2)]),
cena: new FormControl(0, [Validators.required, Validators.min(0.01)])
});
W szablonie HTML formularz "podłącza się" atrybutem [formGroup]="formularz" na znaczniku <form>, a każde pole atrybutem formControlName="nazwa". Sprawdzenie poprawności: formularz.valid (cały formularz), formularz.get('nazwa')?.invalid (pojedyncze pole).
Wbudowane walidatory Angulara (klasa Validators) — bezpośredni odpowiednik Data Annotations z lekcji o ASP.NET Core:
| Walidator Angular | Odpowiednik w C# (Data Annotations) |
|---|---|
Validators.required | [Required] |
Validators.minLength(n) / maxLength(n) | [StringLength] |
Validators.min(n) / max(n) | [Range] |
Validators.email | [EmailAddress] |
Validators.pattern(regex) | własny atrybut walidacyjny z wyrażeniem regularnym |
Walidacja HTML5 (natywna przeglądarki). Niezależnie od Angulara, sam HTML5 oferuje podstawową walidację przez atrybuty znaczników: required, type="email", min/max, pattern — przeglądarka SAMA blokuje wysłanie formularza i pokazuje wbudowany komunikat, jeśli te warunki nie są spełnione. To dobre uzupełnienie (pierwsza linia obrony), ale walidacja Angulara (Reactive Forms) daje PEŁNĄ kontrolę nad wyglądem komunikatów i logiką.
Routing — nawigacja SPA. Plik app.routes.ts definiuje mapowanie adresów URL na komponenty: { path: 'produkty', component: ProduktyComponent }. Znacznik <router-outlet></router-outlet> w głównym komponencie aplikacji wskazuje MIEJSCE, gdzie ma się pojawić aktualnie aktywny komponent-strona — dokładnie ten sam mechanizm co @RenderBody() w Blazor albo @Body w layoucie. Nawigacja z poziomu szablonu: <a routerLink="/produkty">Produkty</a>; z poziomu kodu: wstrzyknięty Router i wywołanie this.router.navigate(['/produkty']).
Parametry w adresie. Trasa { path: 'produkty/:id', component: SzczegolyProduktuComponent } pozwala odebrać wartość przez wstrzyknięty ActivatedRoute: this.route.snapshot.paramMap.get('id') — koncepcyjnie identyczne do parametrów adresu w Razor Pages/Blazor z wcześniejszych lekcji tego kursu.
Zobacz zależności
Schemat
Reactive Forms:
FormGroup (cały formularz)
├── FormControl "nazwa" [Validators.required, minLength(2)]
└── FormControl "cena" [Validators.required, min(0.01)]
│
│ formularz.valid?
niepoprawny ──┴── poprawny
│ │
▼ ▼
pokaż błędy onSubmit() → wyślij dane dalej
Routing SPA:
app.routes.ts:
{ path: "", component: StronaGlownaComponent }
{ path: "produkty", component: ProduktyComponent }
{ path: "produkty/:id", component: SzczegolyProduktuComponent }
app.component.html:
<nav>
<a routerLink="/">Start</a>
<a routerLink="/produkty">Produkty</a>
</nav>
<router-outlet></router-outlet> ← TU wstawiany aktywny komponent
Kliknięcie linku "/produkty" → Router podmienia zawartość <router-outlet>
BEZ przeładowania całej strony (charakterystyczne dla SPA)
Połącz z praktyką
Przykład z życia
Formularz rejestracji nowego produktu w panelu sprzedawcy pokazuje na bieżąco, czy nazwa jest wystarczająco długa i czy cena jest liczbą dodatnią, dokładnie tak jak w Data Annotations z ASP.NET Core — a menu z linkami "Strona główna / Produkty / Kontakt" przełącza widoczną treść błyskawicznie, bez przeładowania całej strony, bo to jedna aplikacja Angular obsługująca kilka "widoków".