Kurs Angular · Moduł 8: Formularze
Walidacja - funkcja z jednym werdyktem
W tej lekcji3
Strażnik u bramy dojo ma proste zadanie: spojrzeć na przybysza i wydać werdykt - wpuścić albo nie. Walidator w Angularze to dokładnie taka funkcja: patrzy na wartość pola i zwraca jeden z dwóch wyników - null, gdy wszystko gra, albo obiekt z opisem błędu, gdy coś jest nie tak. Zapamiętaj ten kontrakt (null = OK), bo powtórzy się w każdej z trzech części tej lekcji.
Walidatory wbudowane
Najczęstsze reguły Angular ma już gotowe - dopinasz je do pola listą. Nie piszesz logiki, tylko wybierasz strażników z półki.
import { Validators } from '@angular/forms';
this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
age: [0, [Validators.min(18), Validators.max(120)]],
phone: ['', Validators.pattern(/^\d{9}$/)],
acceptTerms: [false, Validators.requiredTrue]
});Zwróć uwagę na wzorzec: gdy reguła jest jedna, podajesz ją wprost (Validators.required); gdy kilka, dajesz je w tablicy - wszystkie muszą przejść. requiredTrue to częsta pułapka do zapamiętania: zwykłe required uzna zaznaczony i odznaczony checkbox za wypełniony, a requiredTrue wymaga właśnie zaznaczenia - idealne do zgody na regulamin.
Walidatory własne
Gdy potrzebujesz reguły spoza półki, piszesz strażnika sam. To funkcja zgodna z tym samym kontraktem: dostaje pole, zwraca null lub obiekt błędu.
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
function forbiddenNameValidator(forbidden: string[]): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
if (forbidden.includes(control.value?.toLowerCase())) {
return { forbiddenName: { value: control.value } }; // źle -> obiekt błędu
}
return null; // OK
};
}
// Użycie
this.fb.group({
name: ['', [Validators.required, forbiddenNameValidator(['admin', 'root'])]]
});Przyjrzyj się kształtowi: funkcja zewnętrzna przyjmuje konfigurację (listę zakazanych nazw) i zwraca właściwy walidator - dzięki temu ten sam strażnik obsłuży różne listy. Wewnętrzna funkcja realizuje kontrakt: pasuje do zakazanych - zwraca obiekt { forbiddenName: ... }, w przeciwnym razie null. Klucz obiektu (forbiddenName) to nazwa błędu, po której rozpoznasz go potem w szablonie.
Walidator asynchroniczny
Niektórych rzeczy nie sprawdzisz na miejscu - np. czy nazwa jest zajęta, wie tylko serwer. Wtedy walidator zwraca nie werdykt od razu, lecz strumień, który werdykt przyniesie.
import { AsyncValidatorFn } from '@angular/forms';
import { map, catchError, debounceTime, switchMap, first } from 'rxjs/operators';
import { of } from 'rxjs';
function uniqueNameValidator(service: SamuraiService): AsyncValidatorFn {
return (control: AbstractControl) => {
return of(control.value).pipe(
debounceTime(300), // nie pytaj po każdej literze
switchMap(name => service.checkNameExists(name).pipe(
map(exists => exists ? { nameTaken: true } : null),
catchError(() => of(null)) // błąd sieci -> nie blokuj
)),
first()
);
};
}
// Async validators to TRZECI argument, osobno od synchronicznych
this.fb.group({
name: ['', [Validators.required], [uniqueNameValidator(this.service)]]
});Kontrakt jest ten sam ({ nameTaken: true } albo null), tylko opakowany w strumień, bo odpowiedź przychodzi z opóźnieniem. debounceTime oszczędza serwer, pytając dopiero, gdy użytkownik przestanie pisać, a catchError decyduje, że awaria sieci nie ma blokować formularza. Zapamiętaj jedno miejsce, które łatwo pomylić: walidatory asynchroniczne podajesz jako trzeci argument, oddzielnie od zwykłych - Angular czeka na nie inaczej.
Pamiętaj z tej lekcji jeden kontrakt: walidator to funkcja, która zwraca null przy poprawnej wartości albo obiekt błędu przy złej. Wbudowane bierzesz z półki, własne piszesz tą samą regułą, a asynchroniczne oddają werdykt strumieniem - reszta to szczegóły.
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Co powinien zwrócić custom validator gdy wartość jest poprawna?
2. Co powinien zwrócić custom validator gdy wartość jest NIEpoprawna?
To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Edytor kodu
Uzupełnij własny walidator sprawdzający, czy nazwa samuraja nie zawiera cyfr.
- Układanie w poziomie
Ułóż tokeny zwracanej funkcji walidatora (jedna linia): (control: AbstractControl) => ValidationErrors | null
- Układanie w pionie
Uporządkuj operatory RxJS w łańcuchu walidatora asynchronicznego sprawdzającego unikalność nazwy (kolejność w .pipe(), linia po linii).