Angular2 daje programiście sporo gotowych możliwości ułatwiających walidację formularzy po stronie front-endu. Może to być bardzo pomocne dla użytkownika kiedy w trakcie wypełniania formularza na bieżąco będzie informowany o błędach.
Warto przy tym wspomnieć, że nie zawsze dobrym pomysłem będzie przygotowanie restrykcyjnej walidacji dla formularza. Przykładowo projektując formularz koszyka z zamówieniem w sklepie internetowym, obsłudze sklepu łatwiej będzie poradzić sobie z usunięciem drobnych błędów wpisanych przez klienta (np. błąd w kodzie pocztowym) niż doprowadzić do sytuacji, że poirytowany klient porzuci koszyk i zrezygnuje z zakupu.
Stany formularza w Angular2:
Na stany możemy reagować pokazując lub ukrywając konkretny komunikat oraz stany z przedrostkiem ng-
dodawane, są do pól input jako klasy. To nam idealnie pomaga w stylowaniu formularza np. dodanie czerwonej ramki wokół pola input, gdy zostało ono błędnie wypełnione.
valid | formularz jest poprawnie wypełniony |
invalid | formularz nie jest poprawnie wypełniony |
submitted | formularz został zatwierdzony |
touched | pole formularza zostało dotknięte |
untouched | pole formularza nie zostało dotknięte |
dirty | w polu formularza było coś wpisane (mogło zostać później wykasowane) |
pristine | w polu formularza nie było nic wpisane (jest dziewicze) |
Inne stany, do których mamy dostęp:
status | dane pole (nie cały formularz) jest typu Invalid czy valid |
disabled | dane pole jest typu disabled zwraca true/false |
errors | wskazuje błąd, przez który pole jest invalid |
value | przechowuje wartość input-a wpisaną przez użytkownika |
Walidacja danych w Angular2:
required | dane pole jest wymagane |
minLength(4) | minimalna ilość wpisanych znaków |
maxLength(24) | maksymalna ilość wpisanych znaków |
pattern | dowolny wzór określony przez wyrażenie regularne RegExp |
Przykład formularza z walidacją w HTML:
<form (ngSubmit)="onSubmit(newForm.value)" novalidate="true" #newForm="ngForm">
<div *ngIf="newForm.submitted" class="submittedError">
<span *ngIf="emailRef.errors">Invalid email</span>
<span *ngIf="passRef.errors">Invalid password</span>
</div>
<div>
<div>
<label for="email">E-MAIL
<input type="email" #emailRef="ngModel" pattern="^[a-z0-9-._]+@[a-z0-9.-]+\.[a-z]{2,}$" [(ngModel)]="user.email" name="email" class="form-control" placeholder="Email" required>
<div *ngIf="emailRef.touched&&emailRef.errors?.required" class="bgAlert">This field is required</div>
<div *ngIf="emailRef.touched&&emailRef.errors?.pattern" class="bgAlert">The email is incorrect</div>
</label>
</div>
<div>
<label for="password">PASSWORD
<input type="password" #passRef="ngModel" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}" [(ngModel)]="user.password" name="password" class="form-control" placeholder="Password">
<div *ngIf="passRef.touched&&passRef.errors?.required" class="bgAlert">This field is required</div>
<div *ngIf="passRef.touched&&passRef.errors?.pattern" class="bgAlert">Password required at least 6 characters with: digit, capital letter, lower case letter</div>
</label>
</div>
</div>
<div>
<input type="submit" class="button" value="LOGIN">
</div>
</form>
<style>
.form-control.ng-dirty.ng-invalid {
border: 2px solid rgba(255,0,0,0.9);
}
.form-control.ng-dirty.ng-valid {
border: 2px solid rgba(0,255,0,0.9);
}</style>
Przykład formularza z walidacją w komponencie:
Podejście zalecane, jeżeli do formularza będą pisane testy jednostkowe. Kod HTML jest tu krótszy, ale brakuje też styli. Podane wcześniej stany będą tutaj używane podobnie tyle, że dostęp do nich w tym konkretnym przypadku będzie poprzedzony ścieżką form2.controls
. Poniżej przykład dla pola password.
<form [formGroup]="form2">
<input type="email" placeholder="Email" formControlName="email">
<input type="text" placeholder="street" formControlName="street">
<input type="email" placeholder="Email" formControlName="email2">
<input type="password" placeholder="password" formControlName="password">
{{ form2.controls.password.valid }}
{{ form2.controls.password.dirty }}
{{ form2.controls.password.pristine }}
{{ form2.controls.password.status }}
{{ form2.controls.password.disabled }}
{{ form2.controls.password.touched }}
{{ form2.controls.password.errors | json }}
{{ form2.controls.password.value }}
</form>
A teraz właściwa walidacja w komponencie. Wszystkie pola wymagane, a oprócz tego street przynajmniej 3 znaki, e-mail 2 pattern, password pattern.
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-member',
templateUrl: './member.component.html',
styleUrls: ['./member.component.css']
})
export class MemberComponent implements OnInit {
form2: any;
constructor(private fb: FormBuilder) { }
ngOnInit() {
this.form2 = this.fb.group({
email: ['', Validators.required],
street: ['', [Validators.minLength(3), Validators.required]],
email2: ['', [Validators.pattern("'^[a-z0-9-._]+@[a-z0-9.-]+\.[a-z]{2,}$"),
Validators.required]],
password: ['', [Validators.pattern('(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}'),
Validators.required]]
});
}
}