Formulare - 2 abordari:
- bazata pe template - Angular deduce obiectul formularului, din DOM
- reactiva - formularul este creat in mod programatic si este sincronizat cu DOM-ul
TEMPLATE
In app.module.ts, @NgModule -> imports -> FormsModule
<form
(ngSubmit)="onSubmit(f)" #f="ngForm">
<input type="text" id="username"
name="username" ngModel>
</form>
In TypeScript:
onSubmit (form: NgForm) {
// NgForm este un formular creat automat de Angular
console.log(form.value['username']);
// sau form.value.username
}
Altfel - daca vrei sa accesezi formularul nu numai la completarea lui, ci si inainte:
@ViewChild('f') signupForm: NgForm;
// ngModel aplicat pe tag-ul html iti da voie sa recuperezi obiectul in TypeScript
// onSubmit() poate deveni acum fara parametru de intrare
Cateva din alte proprietati furnizate de NgForm:
- dirty: daca formularul are vreun camp schimbat
- enabled, disabled
- valid, invalid
- touched: daca a fost facut click pe formular
Validare input:
- adaugare required in fisierul html, pe input-ul dorit
- alti validatori:
email, lista completa
aici => validitatea se va reflecta in atributele din NgForm
- Angular adauga dinamic clase css pe input-uri care reflecta starea, folosindu-le putem stiliza input-urile pentru a avertiza utilizatorul:
input .ng-invalid .ng-touched {
border: 1px solid red;
}
Afisare mesaje de eroare:
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
<input type="text" id="myemail"
name="myemail" ngModel #email="ngModel">
</form>
<span class="help-block"
*ngIf="!email.valid && email.touched">Please enter valid email</span>
Inserare valori initiale:
defaultQuestion='pet';
<select id='secret'
[ngModel]="defaultQuestion" name="secret">
<option value="pet">What was your first pet?</option>
<option value="teacher">What was your first teacher?</option>
</select>
Valori predefinite in TypeScript
@ViewChild('f') myForm: NgForm;
this.myForm.
setValue ({
username: 'myChoice',
secret: 'pet'
// trebuiesc adaugate toate campurile
});
// suprascrie doar campurile care ne intereseaza:
this.myForm.
form.
patchValue({
userData: {
username: 'something'
}
});
Curatare formular: this.myForm.reset();
Two-way binding:
<textarea name="questionAnswer" rows="3"
[(ngModel)]="answer"/>
<p> Your reply:
{{answer}} </p>
// unde answer trebuie sa fie declarat ca empty string in TypeScript
ngModelGroup - pentru a se aplica la mai mult de un singur camp
<div
ngModelGroup="userData" #userData="ngModelGroup">
<!-- campuri -->
</div>
<p *ngIf="!
user.Data.valid &&
userData.touched">User data invalid!</p>
Butoane radio
<div class="radio" *ngFor="let gender of genders">
<label>
<input type="radio" name="gender" [value]="gender" ngModel> {{ gender }}
</label>
</div>
ABORDAREA REACTIVA
- nu mai este nevoie de import
FormsModule, se inlocuieste cu
ReactiveFormsModule
signupForm:
FormGroup;
ngOnInit() {
this.signupForm = new
FormGroup({
'username': new
FormControl(null),
'email': new
FormControl(null),
'gender': new
FormControl('male')
});
}
onSubmit() { }
// Html:
<form (ngSubmit)="onSubmit()"
[formGroup]="signupForm">
<input type="text" id="username"
formControlName="username">
<input type="text" id="email"
formControlName="email">
<input type="radio" id="gender"
formControlName="gender">
</form>
Validare prin metoda reactiva:
this.signupForm = new FormGroup({
'username': new FormControl(null,
Validators.required),
// referinta la metoda de validare
'email': new FormControl(null,
[Validators.required, Validators.email]),
'gender': new FormControl('male')
});
Afisarea validarilor
<span *ngIf="!signupForm.
get('username').valid && signupForm.
get('username').touched">Please enter a valid username!</span>
Grupare reactiva
- elementele se aseaza intr-un <div
formGroupName="userData">
- se actualizeaza
span cu noua cale catre elementul validat:
<span *ngIf="!signupForm.get('
userData.username').valid && signupForm.get('
userData.username').touched">Please enter a valid username!</span>
FormArray
<div formArrayMode="
hobbies">
<h4>Your hobbies</h4>
<button type="button" (click)="onAddHobby()">Add hobby</button>
<div class="form-group" *ngFor="let hobbyControl of getControls(); let i = index">
<input type="text"
[formControlName]="i">
</div>
</div>
// TypeScript:
ngOnInit() {
this.signupForm = new FormGroup({
'username': new FormControl(null),
'email': new FormControl(null),
'gender': new FormControl('male'),
'hobbies': new FormArray([])
});
}
getControls() {
return (
<FormArray>this.signupForm.get('hobbies')).controls;
}
onAddHobby() {
const control = new FormControl(null, Validators.required);
(
<FormArray>this.signupForm.get('hobbies')).push(control);
// explicit casting
}
Creare propriii validatori
forbiddenNames(control: FormControl):
{(s: string): boolean} {
// format output: {'mesaj de eroare': true}
if (this.forbiddenUsernames.indexOf(control.value) !== -1) {
return {'
name is forbidden': true};
}
return null;
// validation is successful
}
this.signupForm = new FormGroup({
'username': new FormControl(null,
[Validators.required, this.forbiddenNames.bind(this)]),
'email': new FormControl(null, [Validators.required, Validators.email]),
'gender': new FormControl('male'),
'age': new FormControl(null, Validators.pattern(
/^[1-9]+[0-9]+$'/))
});
// binding-ul este pt a ne asigura ca this in metoda este ceea ce trebuie sa fie
Angular adauga erorile pe fiecare
Control -> errors:
<span *ngIf="signupForm.get('userData.username').
errors[
'name is forbidden']">This name is invalid!</span>
Validatori asincroni
forbiddenEmails(control: FormControl): Promise<any> | Observable<any> {
const promise = new Promise<any>((resolve, reject) => {
setTimeout(() -> {
if (control.value === 'someAddress@yahoo.com') {
resolve({'emailIsForbidden': true});
} else {
resolve(null);
}
}, 1500);
// simulare asincronicitate
});
return promise;
}
// Html:
this.signupForm = new FormGroup({
'username': new FormControl(null, [Validators.required, this.forbiddenNames.bind(this)]),
'email': new FormControl(null, [Validators.required, Validators.email], this.forbiddenEmails.bind(this)), // al 3-lea arg este rezervat pt validatori asincroni
'gender': new FormControl('male')
});
// TypeScript:
this.signupForm.valueChanged.subscribe(value => console.log(value));
this.signupForm.statusChanged.subscribe(status=> console.log(status)); // VALID, INVALID, PENDING (async)
setValue() si
patchValue() sunt in continuare disponibile pe obiectul FormGroup.
reset() de asemenea.