-
Notifications
You must be signed in to change notification settings - Fork 0
Formulaires
Angular propose deux approches pour gérer les formulaires : les formulaires template-driven (pilotés depuis le template, avec ngModel) et les formulaires réactifs (pilotés depuis la classe TypeScript, avec FormGroup/FormControl). Cette page couvre les deux, avec cours, exemple et exercice pour chacune des 4 leçons.
Prérequis : avoir lu les pages Composants et Routage.
-
C'est quoi ? Un ensemble d'outils Angular (
ngModel,FormGroup/FormControl, validateurs) pour lier des champs de saisie HTML à des données de la classe du composant. - À quoi ça sert ? À récupérer, contrôler et valider ce que l'utilisateur saisit (connexion, inscription, recherche, contact...) avant de l'utiliser ou de l'envoyer à une API.
- Pourquoi ? Presque toute application interagit avec l'utilisateur via des formulaires. Sans validation ni gestion propre des saisies, on s'expose à des données incorrectes ou incomplètes envoyées au serveur.
- Formulaires
- Obtention des valeurs de contrôle de formulaire
- Formulaires réactifs
- Validation des formulaires
L'approche la plus simple pour créer un formulaire consiste à utiliser le module FormsModule et la directive ngModel, qui crée une liaison bidirectionnelle (two-way binding) entre un champ de saisie et une propriété de la classe : la propriété se met à jour quand l'utilisateur tape, et le champ se met à jour si la propriété change dans le code.
La syntaxe [(ngModel)]="propriete" (surnommée "banana in a box") combine property binding ([ngModel]) et event binding ((ngModelChange)).
import { Component, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-profil-form',
imports: [FormsModule],
template: `
<label>
Nom :
<input [(ngModel)]="nom" name="nom">
</label>
<p>Bonjour, {{ nom() }} !</p>
`,
})
export class ProfilForm {
nom = signal('');
}Note : à partir d'Angular récent,
[(ngModel)]fonctionne directement avec dessignal(). Chaque<input>utilisantngModeldans un<form>doit avoir un attributname.
Crée un composant FormulaireContact avec un champ nom et un champ email, tous deux liés via [(ngModel)] à des signaux. Affiche un résumé "Nom : ... / Email : ..." qui se met à jour en temps réel.
Solution
import { Component, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-formulaire-contact',
imports: [FormsModule],
template: `
<label>Nom : <input [(ngModel)]="nom" name="nom"></label>
<label>Email : <input [(ngModel)]="email" name="email"></label>
<p>Nom : {{ nom() }} / Email : {{ email() }}</p>
`,
})
export class FormulaireContact {
nom = signal('');
email = signal('');
}Il n'est pas toujours nécessaire d'utiliser ngModel. On peut aussi récupérer la valeur d'un champ directement depuis l'événement DOM, avec un event binding classique (input) ou (change), et $event.target. C'est une approche plus proche du HTML natif, utile pour des formulaires simples ou ponctuels.
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-recherche-produit',
template: `
<input (input)="onSaisie($event)" placeholder="Nom du produit">
<p>Vous cherchez : {{ recherche() }}</p>
`,
})
export class RechercheProduit {
recherche = signal('');
onSaisie(event: Event) {
const valeur = (event.target as HTMLInputElement).value;
this.recherche.set(valeur);
}
}Crée un composant CalculateurAge avec un <input type="number"> pour l'année de naissance. À chaque saisie, calcule et affiche l'âge approximatif (année courante moins année saisie), sans utiliser ngModel.
Solution
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-calculateur-age',
template: `
<input type="number" (input)="onSaisie($event)" placeholder="Année de naissance">
<p>Âge approximatif : {{ age() }} ans</p>
`,
})
export class CalculateurAge {
age = signal(0);
onSaisie(event: Event) {
const anneeNaissance = Number((event.target as HTMLInputElement).value);
const anneeActuelle = new Date().getFullYear();
this.age.set(anneeActuelle - anneeNaissance);
}
}Les formulaires réactifs (module ReactiveFormsModule) déplacent la logique du formulaire dans la classe TypeScript plutôt que dans le template. On modélise le formulaire avec un FormGroup composé de FormControl, ce qui offre un typage fort, une meilleure testabilité et davantage de contrôle — recommandé pour des formulaires complexes.
import { Component } from '@angular/core';
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-inscription',
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="formulaire" (ngSubmit)="onSoumission()">
<input formControlName="nom" placeholder="Nom">
<input formControlName="email" placeholder="Email">
<button type="submit">S'inscrire</button>
</form>
`,
})
export class Inscription {
formulaire = new FormGroup({
nom: new FormControl(''),
email: new FormControl(''),
});
onSoumission() {
console.log(this.formulaire.value);
}
}Crée un FormGroup nommé formulaireLogin avec deux FormControl : identifiant et motDePasse. Construis le template avec formGroup, formControlName et un bouton de soumission qui affiche this.formulaireLogin.value dans la console.
Solution
import { Component } from '@angular/core';
import { FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-login',
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="formulaireLogin" (ngSubmit)="onSoumission()">
<input formControlName="identifiant" placeholder="Identifiant">
<input formControlName="motDePasse" type="password" placeholder="Mot de passe">
<button type="submit">Se connecter</button>
</form>
`,
})
export class Login {
formulaireLogin = new FormGroup({
identifiant: new FormControl(''),
motDePasse: new FormControl(''),
});
onSoumission() {
console.log(this.formulaireLogin.value);
}
}Angular fournit des validateurs intégrés (Validators.required, Validators.email, Validators.minLength, etc.) qu'on associe à un FormControl. L'état du formulaire (valid, invalid, touched, dirty) permet d'afficher des messages d'erreur ciblés et de désactiver la soumission tant que le formulaire n'est pas valide.
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-inscription',
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="formulaire" (ngSubmit)="onSoumission()">
<input formControlName="email" placeholder="Email">
@if (formulaire.controls.email.invalid && formulaire.controls.email.touched) {
<p class="erreur">Email invalide ou manquant.</p>
}
<button type="submit" [disabled]="formulaire.invalid">S'inscrire</button>
</form>
`,
})
export class Inscription {
formulaire = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
});
onSoumission() {
if (this.formulaire.valid) {
console.log(this.formulaire.value);
}
}
}Reprends le formulaireLogin de l'exercice précédent et ajoute des validateurs : identifiant obligatoire avec une longueur minimale de 3 caractères, motDePasse obligatoire avec une longueur minimale de 8 caractères. Affiche un message d'erreur sous chaque champ invalide et touché, et désactive le bouton de soumission tant que le formulaire est invalide.
Solution
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-login',
imports: [ReactiveFormsModule],
template: `
<form [formGroup]="formulaireLogin" (ngSubmit)="onSoumission()">
<input formControlName="identifiant" placeholder="Identifiant">
@if (formulaireLogin.controls.identifiant.invalid && formulaireLogin.controls.identifiant.touched) {
<p class="erreur">L'identifiant doit contenir au moins 3 caractères.</p>
}
<input formControlName="motDePasse" type="password" placeholder="Mot de passe">
@if (formulaireLogin.controls.motDePasse.invalid && formulaireLogin.controls.motDePasse.touched) {
<p class="erreur">Le mot de passe doit contenir au moins 8 caractères.</p>
}
<button type="submit" [disabled]="formulaireLogin.invalid">Se connecter</button>
</form>
`,
})
export class Login {
formulaireLogin = new FormGroup({
identifiant: new FormControl('', [Validators.required, Validators.minLength(3)]),
motDePasse: new FormControl('', [Validators.required, Validators.minLength(8)]),
});
onSoumission() {
if (this.formulaireLogin.valid) {
console.log(this.formulaireLogin.value);
}
}
}
Wiki basé sur le tutoriel officiel Apprendre Angular (angular.dev) — Accueil · Documentation officielle Angular
Démarrage
Le tutoriel (25 leçons)