Angular:Reactive Forms

folder Projet: angularApp
Reactive Forms est un module permettant de créer des formulaires et gérer l'état des inputs ,Reactive Forms contient un ensemble de classes FormControl, FormGroup, FormArray and FormBuilder...

FormControl

Permet de gérer et valider l'état d'un input

app.component.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {

constructor() {
}

//un objet Etudiant
etudiant={
nom:"",
prenom:"",
groupe:"",
age:0,
}
//pour chaque attribut de l'objet etudiant on doit créer un FormControl

Fnom = new FormControl({value:"Valeur par défaut", disabled: false});
Fage = new FormControl({value:"0", disabled: true});// sera disabled =>not editing
Fprenom = new FormControl("valeur par défaut");
Fgroupe = new FormControl("valeur par défaut");
//on peut activer ou désactiver un input
activerAge()
{
this.Fage.enable(); //ou this.Fage.disable(); pour disbale

}
//on peut changer la valeur
setGroupe()
{
this.Fgroupe.setValue("Groupe1");
}
valider()
{
this.etudiant.nom=this.Fnom.value;
this.etudiant.age=this.Fage.value;
this.etudiant.prenom=this.Fprenom.value;
this.etudiant.groupe=this.Fgroupe.value;
}
}


app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">

<table>
<tr>
<td>Nom</td>
<td><input [formControl]="Fnom"></td>
</tr>
<tr>
<td>Prenom</td>
<td><input [formControl]="Fprenom"></td>
</tr>
<tr>
<td>Groupe</td>
<td><input [formControl]="Fgroupe" [attr.disabled]="true"></td>
</tr>
<tr>
<td>Age</td>
<td><input [formControl]="Fage">
<button (click)="activerAge()">Activé</button>
</td>
</tr>
<tr>
<td></td>
<td>
<button (click)="valider()">Valider</button>
</td>
</tr>
</table>
Nom :{{Fnom.value}}<br/>
Prenom :{{Fnom.value}}<br/>
Age :{{Fnom.value}}<br/>
Groupe :{{Fgroupe.value}}<br/>
<hr/>
Etudiant:<br/>
Nom :{{etudiant.nom}}<br/>
Prenom :{{etudiant.prenom}}<br/>
Age :{{etudiant.age}}<br/>
Groupe :{{etudiant.groupe}}<br/>
</div>

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '@angular/common/http';
import { ReactiveFormsModule } from '@angular/forms';

//.....

@NgModule({
declarations: [
AppComponent,
//.....
imports: [
BrowserModule,
AppRoutingModule,
FormsModule ,
HttpClientModule,
ReactiveFormsModule,
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }

FromControl +Validation

FormControl permet de valider la valeur d'un control avec la classe Validators qui contient les attributs suivants: min, max, required, email, minLength, maxLength and pattern.

app.component.ts

import { Component } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
username = new FormControl('', [Validators.minLength(5), Validators.maxLength(10)]);
company = new FormControl('', [Validators.required]);
primaryEmail = new FormControl('', [Validators.email]);
emailPattern = "^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$";
secondaryEmail = new FormControl('', [Validators.pattern(this.emailPattern)]);
age = new FormControl('', [Validators.min(18), Validators.max(50)]);

}


app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<table>
<tr><td>Username: </td><td>
<input [formControl]="username">
<div *ngIf="username.hasError('minlength')" class="error">
Minimum length should be 5.
</div>
<div *ngIf="username.hasError('maxlength')" class="error">
Maximum length should be 10.
</div> </td></tr>
<tr><td>Company: </td><td>
<input [formControl]="company">
<div *ngIf="company.hasError('required')" class="error">
Name required.
</div> </td></tr>
<tr><td>Primary Email: </td><td>
<input [formControl]="primaryEmail">
<div *ngIf="primaryEmail.hasError('email')" class="error">
Email not valid.
</div> </td></tr>
<tr><td>Secondary email: </td><td>
<input [formControl]="secondaryEmail">
<div *ngIf="secondaryEmail.hasError('pattern')" class="error">
Email not valid.
</div></td></tr>
<tr><td>Age: </td><td>
<input [formControl]="age">
<div *ngIf="age.hasError('min')" class="error">
Minimum age should be 18.
</div>
<div *ngIf="age.hasError('max')" class="error">
Maximum age should be 50.
</div> </td></tr>
</table>
</div>

FormGroup

Permet de gérer un groupe de FromControl

app.component.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {

constructor() {
}

//un objet Etudiant
etudiant={
nom:"",
prenom:"",
groupe:"",
age:0,
genre:"F",
profile:''
}

profiles = [
{name: 'Developer', shortName: 'dev'},
{name: 'Manager', shortName: 'man'},
{name: 'Director', shortName: 'dir'}
];
//pour chaque attribut de l'objet etudiant on doit créer un FormControl
EtudiantForm = new FormGroup({
Fnom : new FormControl({value:"Valeur par défaut", disabled: false}),
Fage :new FormControl({value:"0", disabled: true}),//ne sera pas disabled not editing
Fprenom : new FormControl("valeur par défaut"),
Fgroupe : new FormControl("valeur par défaut"),
Fgenre: new FormControl('F'),
Fprofile: new FormControl(this.profiles[0].shortName)

});
activerAge()
{
this.EtudiantForm.get('Fage')!.enable({ emitEvent: true });
}
//on peut changer la valeur
setGroupe()
{
this.EtudiantForm.patchValue({Fgroupe: 'Groupe1'});

}
resetForm()
{
this.EtudiantForm.reset();
}
valider()
{
this.etudiant.nom= this.EtudiantForm.get('Fnom')!.value;
this.etudiant.age= this.EtudiantForm.get('Fage')!.value;
this.etudiant.prenom= this.EtudiantForm.get('Fprenom')!.value;
this.etudiant.groupe= this.EtudiantForm.get('Fgroupe')!.value;
}
}


app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<form [formGroup]="EtudiantForm" (ngSubmit)="valider()">
<table>
<tr>
<td>Nom</td>
<td><input formControlName="Fnom"></td>
</tr>
<tr>
<td>Prenom</td>
<td><input formControlName="Fprenom"></td>
</tr>
<tr>
<td>Groupe</td>
<td><input formControlName="Fgroupe" [attr.disabled]="true"></td>
</tr>
<tr>
<td>Age</td>
<td><input formControlName="Fage">
<input type="button" (click)="activerAge()" value="Activer"/>
</td>
</tr>
<tr>
<td>Genre</td>
<td>
<input type="radio" formControlName="Fgenre" value="M"> M
<input type="radio" formControlName="Fgenre" value="F" > F
</td>
</tr>
<tr>
<td>Profile</td>
<td>
<select formControlName="Fprofile">
<option *ngFor="let pf of profiles" [ngValue]="pf.shortName">
{{ pf.name }}
</option>
</select>
</td>
</tr>
<tr>
<td><input type="reset"> </td>
<td><input type="submit"> </td>
</tr>
</table>
</form>
{{EtudiantForm.get('Fnom')!.value}}<br/>
{{EtudiantForm.get('Fprenom')!.value}}<br/>
{{EtudiantForm.get('Fage')!.value}}<br/>
{{EtudiantForm.get('Fprofile')!.value}}<br/>
{{EtudiantForm.get('Fgenre')!.value}}<br/>
<hr/>
Etudiant:<br/>
Nom :{{etudiant.nom}}<br/>
Prenom :{{etudiant.prenom}}<br/>
Age :{{etudiant.age}}<br/>
Groupe :{{etudiant.groupe}}<br/>
</div>

FormGroup et la validation

FormGroup permet de valider les FormControl à l'aide Validators classe

app.component.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {

constructor() {
}
userForm = new FormGroup({
name: new FormControl('', [Validators.required, Validators.maxLength(10)]),
age: new FormControl('', Validators.required)
});

//Vérifier la validation du name
get userName(): any {
return this.userForm.get('name');
}

}

app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<form [formGroup]="userForm">
<div>
Name: <input formControlName="name" placeholder="Enter Name">
<label *ngIf="userName.invalid" [ngClass] = "'error'"> au moins 10 caractères </label>
</div>
<div>
Age: <input formControlName="age" placeholder="Enter Age">
<label *ngIf="userForm.get('age')!.invalid" [ngClass] = "'error'"> Age is required. </label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
</div>

FormArray

FormArray permet de gérer les valeurs et la validité de FormControl, FormGroup and FormArray ,permet aussi d'ajouter ou supprimer FormControl

FormArray contient les fonctions suivantes:

  1. at(): Returns the AbstractControl instance for the given index. The AbstractControl is the base class for FormControl, FormGroup and FormArray classes.
  2. push(): Inserts the new AbstractControl at the end of array.
  3. insert(): Inserts a new AbstractControl at the given index in the array.
  4. removeAt(): Removes the control at the given index in the array.
  5. setControl(): Sets a new control replacing the old one.
  6. setValue(): Sets the value to every control of this FormArray.
  7. patchValue(): Patches the value to available controls starting from index 0.
  8. reset(): Resets the values.
  9. getRawValue(): The aggregate value of the array.
  10. clear(): Removes all controls in this FormArray.

app.component.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, FormArray,Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
personneForm = new FormGroup({
name: new FormControl('', [ Validators.required ]),
parents: new FormArray([
new FormControl('mère '),
new FormControl('père')
])
});
get name() {
return this.personneForm.get('name') as FormControl;
}
get parents() {
return this.personneForm.get('parents') as FormArray;
}

onFormSubmit()
{
let name=this.personneForm.get('name')!.value;
let parents=this.personneForm.get('parents') as FormArray;

for(let i = 0; i < parents.length; i++) {
console.log(this.parents.at(i).value);
}
}

}



app.component.ts

<form [formGroup]="personneForm" (ngSubmit)="onFormSubmit()">
<div>
Name: <input formControlName="name">
<label *ngIf="name.hasError('required')"> Enter Name. </label>
</div>
parents:
<div formArrayName="parents">
<div *ngFor="let cm of parents.controls; index as i">
<input [formControlName]="i">
</div>
</div>
<button>SUBMIT</button>
</form>

FormBuilder

FormBuilder permet de créer un formulaire contenant FormGroup, FormControl et FormArray
Contenant les fonctions suivnates:
  1. group(): Creates FormGroup.
  2. control(): Creates FormControl.
  3. array(): Creates FormArray.

app.component.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, FormArray,Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private formBuilder: FormBuilder) { }
etudiantForm = this.formBuilder.group({
nom: '',
prenom: '',
age: 0,
genre: '',
isActive:false
});

onFormSubmit()
{
console.log(this.etudiantForm.get('prenom')!.value)
}
}


app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<form [formGroup]="etudiantForm" (ngSubmit)="onFormSubmit()">
<table>
<tr>
<td>Nom</td>
<td><input formControlName="nom"></td>
</tr>
<tr>
<td>Prenom</td>
<td><input formControlName="prenom"> </td>
</tr>
<tr>
<td>Age</td>
<td><input formControlName="age" type="number"> </td>
</tr>
<tr>
<td>Genre</td>
<td><input type="radio" formControlName="genre" value="M"> M
<input type="radio" formControlName="genre" value="F" > F</td>
</tr>
<tr>
<td>Active?</td>
<td><input type="checkbox" formControlName="isActive"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="submit"/> </td>
</tr>
</table>
</form>

FormBuilder+FormArray Validation

app.component.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup, FormBuilder, FormArray,Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private formBuilder: FormBuilder) { }

etudiantsForm = this.formBuilder.group({
filiere: ['', Validators.required],
groupe: ['', Validators.required],
etudiants: this.formBuilder.array(
[
new FormControl()
], [Validators.required, Validators.maxLength(5)])
});
//recupérer les fomControll pour la validation
get groupe() {
return this.etudiantsForm.get('groupe') as FormControl;
}
get etudiants() {
return this.etudiantsForm.get('etudiants') as FormArray;
}
//ajouter un nouveau controll dans le tableau etudiant
addEtudiantControl() {
this.etudiants.push(new FormControl());
}
//supprimer le controle du index =>index
deleteEtudiantControl(index: number) {
this.etudiants.removeAt(index);
}
insertEtudiantControl() {
this.etudiants.insert(1, new FormControl());
}
//modifier la valeur d'un controler
setEtudiantControl(index:number) {
this.etudiants.setControl(index, new FormControl('nom'));
}
//initialiser les attribut des étudiants
setEtudiantValue() {
this.clearEtudiantControls();
this.addEtudiantControl();
this.addEtudiantControl();
this.addEtudiantControl();
this.etudiants.setValue(['a', 'b', 'c']);
}
//modifier les valeurs des controllers
patchEtudiantValue() {
this.etudiants.patchValue(['x', 'y', 'z']);
}
//reset le tableau
resetetudiants() {
this.etudiants.reset();
}
//effacer le tableau
clearEtudiantControls() {
this.etudiants.clear();
}
onFormSubmit() {
//récupérer un étudiants avev sa position
const etudiants = this.etudiants.at(0);
console.log(etudiants.value);
//récupérer le nombre d'étudiants
const rawVal = this.etudiants.getRawValue();
//reinitialiser le form
this.etudiantsForm.reset();
}
}




app.component.html

<div style="padding:10px;border:1px solid #ddd;margin:10px;">
<form [formGroup]="etudiantsForm" (ngSubmit)="onFormSubmit()">
<table>
<tr>
<td>filiere </td>
<td><input formControlName="filiere"></td>
</tr>
<tr>
<td>Groupe</td>
<td><input formControlName="groupe"></td>
</tr>
</table>
<span>Liste etudiants:</span><br/>
<div formArrayName="etudiants">

<ul class="list-group" *ngFor="let emp of etudiants.controls; let i = index" >
<li class="list-group-item"> <b>Etudiant {{i + 1}} : </b>
<input [formControlName]="i">
<button type="button" (click)="deleteEtudiantControl(i)">Delete</button>
</li>
</ul>
</div>
<div class="btn-group" role="group" aria-label="Basic mixed styles example">
<button type="button" class="btn btn-primary" (click)="addEtudiantControl()">Add</button><br/>
<button type="button" class="btn btn-success" (click)="insertEtudiantControl()">Add at 2</button><br/>
<button type="button" class="btn btn-warning" (click)="patchEtudiantValue()">Patch</button><br/>
<button type="button" class="btn btn-info" (click)="setEtudiantValue()">default list</button><br/>
<button type="button" class="btn btn-primary" (click)="setEtudiantControl(2)">defaut po 2</button><br/>
<button type="button" class="btn btn-info" (click)="resetetudiants()">Reset</button><br/>
<button type="button" class="btn btn-danger" (click)="clearEtudiantControls()">clear</button><br/><br/>
<button type="button" class="btn btn-primary" [disabled]="etudiantsForm.invalid">SUBMIT</button>
</div>
</form>
</div>