Cześć po 2 tygodniowej przerwie! W dzisiejszym artykule VALIDATION SERVICE – usprawniamy wyświetlanie errorów. W poprzednich artykułach pokazałem jak wyświetlać błędy walidacji na widoku. Wykonywałem to w następujący sposób:
1 2 3 4 5 6 7 |
<span *ngIf="modelForm.controls['firstname'].dirty && modelForm.controls['firstname'].errors?.startsWith"> Must start with {{ modelForm.controls['firstname'].errors?.startsWith }} </span> <span *ngIf="modelForm.controls.positions.controls[i].dirty && modelForm.controls['positions'].controls[i].errors?.oneRequired"> At least one field is required </span> |
Jeśli powyższy kod nie jest dla Ciebie jasny, zalecam zapoznanie się z I częścią artykułu o Reactive Forms, a najlepiej przeczytanie wszystkich części dotyczących Reactive Forms.
A teraz wyobraź sobie, że masz 10 inputów, w tym różne typy errorów (Required, minLength, maxLength, pattern etc). Zaczyna pachnieć spaghetti code? O tak…
Zdecydowanie będzie lepiej, jeśli nasze powyższe dwa elementy span z errorami, wyglądałyby następująco:
1 2 3 |
<error-message [control]="modelForm.controls['lastname']"></error-message> <error-message [control]="modelForm.controls.positions.controls[i]"></error-message> |
Żadnych dirty, logiki, tekstu, nazwy errora, wyłącznie referencja do obiektu = profit.
Pokażę, jak przygotować serwis oraz komponent, który zwróci nam odpowiedni typ błędu. Po co nam to?
- wszystkie teksty errorów trzymamy w jednym obiekcie, w przypadku zmiany możemy za jednym ruchem zmienić teksty w całej aplikacji
- czystsza templatka
- szybsza walidacja formularzy, nie tracimy zbędnego czasu na rozpisywanie
Poniżej link do plunkera, który zawiera kod z dalszej części artykułu:
Powyższy live example, jest on kontynuacją poprzedniego plunkera dotyczącego custom validatorów. W tym artykule interesują nas wyłącznie pliki:
- app/validation.service.ts
- app/error-message.component.ts
- app/error-message.component.html
- app/model-driven-form.component.html
Czas do kodu!
Validation Serivce
Zaczniemy od przygotowania serwisu, który będzie zwracać nam odpowiedni error. Jest to klasa z jedną metodą statyczną, która przyjmuje dwa argumenty – klucz w obiekcie, który zwraca walidator, oraz opcjonalnie wartość walidatora.
(app/validation.service.ts)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
export class ValidationService { static getValidationMessage(validator : string, validatorValue? : any) { const messages = { 'required': 'This field is required', 'oneRequired': 'At least one field is required', 'minlength': `Min length is ${validatorValue.requiredLength} characters`, 'startsWith': `This field must start with ${validatorValue}`, 'digits': 'This field must be a digit' }; return messages[validator]; } } |
Istotne, aby nasze klucze w obiekcie messages, nazywały się dokładnie tak jak klucze w obiekcie zwracanym przez walidator. Do obiektu messages dodajemy wszystkie możliwe walidacje, których używamy. Walidatory digits, oneRequired, startsWith stworzyłem w poprzednim artykule.
Serwis gotowy. Czas na komponent, wyświetlający odpowiedni error na widoku.
Error Message Component
Nasz komponent jest mały i prosty. Składa się wyłącznie z inputa i jednego gettera. Input() będzie odbierał referencję do obiektu, który reprezentuje kontrolkę lub grupę w formularzu (FormControl lub FormGroup).
Natomiast getter zwróci nam odpowiedni error z pomocą serwisu.
(app/error-message.component.ts)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import { Component, Input } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { ValidationService } from './validation.service'; @Component({ moduleId: module.id, selector: 'error-message', templateUrl: './error-message.component.html' }) export class ErrorMessageComponent { @Input() control: FormGroup | FormControl; get errorMessage() { for (let key in this.control.errors) { if (this.control.errors.hasOwnProperty(key) && this.control.dirty) { return ValidationService.getValidationMessage(key, this.control.errors[key]); } } return null; } } |
Jeszcze prosta templatka errora, którą oczywiście możesz ostylować wedle upodobań.
(app/error-message.component.html)
1 2 3 |
<div *ngIf="errorMessage !== null" class="error-container"> <span class="error-text">{{ errorMessage }}</span> </div> |
Oraz użycie na widoku:
(app/model-driven-form.component.html)
1 2 |
<input class="form-control" name="lastname" formControlName="lastname"> <error-message [control]="modelForm.controls['lastname']"></error-message> |
Jak widzimy, w data-bound [control], przekazujemy wyłącznie referencję do danej kontrolki / grupy. Możesz również sparametryzować error-message komponent i np decydować czy dirty / touched / pristine występuje w danej walidacji.
Wyświetlanie errorów nigdy nie było przyjemniejsze!:-) Link do plunkera:
Dodaj komentarz