Angular FORMS
Reactive Forms & Template-Driven Form
Etant un framework front-end complet, Angular possède son propre ensemble de bibliothèques pour
la création de formulaires complexes.
Angular permet de :
1. Modéliser le formulaire.
2. Permettre la gestion et la validation du formulaire.
La dernière version d'Angular dispose de deux stratégies puissantes de création de
formulaires :
1. Approche basée Template (Template-driven forms)
2. Approche réactive (Reactive forms)
D’après la documentation officielle d’Angular :
Les Reactive forms sont plus robustes, plus évolutifs, réutilisables et testables. Si les
formulaires constituent un élément clé de notre application, c’est le choix idéal.
Les Template-driven forms sont utiles pour ajouter un formulaire simple à une application,
tel qu'un formulaire d'inscription. Ils sont faciles à ajouter à une application, mais ils ne sont
pas aussi évolutifs que les formulaires réactifs. C’est un choix idéal si nous avons des
exigences de base et une logique pouvant être gérées uniquement dans le template.
Basé sur un formulaire standard HTML
Tout d'abord, il faut savoir que les formulaires Angular se basent sur des éléments HTML classiques.
En HTML, un formulaire standard est englobé par une balise <form> qui contient des champs définis
par les balises <input>, <textarea> ou <select>.
Le formulaire contiendra aussi un bouton de type “submit” qui permettra de déclencher la validation
du formulaire.
<form>
<div class="mb-3">
<label for="firstname" class="form-label">Firstname</label>
<input id="firstname" type="text" class="form-control" />
</div>
<div class="mb-3">
<label for="lastname" class="form-label">Lastname</label>
<input id="lastname" type="text" class="form-control" />
</div>
<div class="mb-3">
<label for="age" class="form-label">Age</label>
<input id="age" type="number" class="form-control" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Notre objectif est d'utiliser les outils fournis par Angular, pour manipuler et accéder aux valeurs de
notre formulaire.
Dans ce TP, je vais utiliser des classes CSS (form-
label, form-control, etc.) pour styliser mes
formulaires. Ces classes CSS n'ont aucun impact
sur le fonctionnement des formulaires, elles
servent uniquement à les styliser.
Reactive Forms avec FormGroup et FormControl
Les Reactive Forms est aujourd'hui l'approche conseillée par Angular. Elle permet de gérer à la fois les
formulaires les plus simples, mais aussi les plus complexes. Vous ne pouvez pas vous tromper en
choisissant les Reactive Forms pour vos formulaires.
Lorsqu'on utilise des formulaires avec Angular, nous allons retrouver des FormGroups et
des FormControls.
Avec les Reactive Forms, un formulaire va correspondre à un FormGroup.
Un FormGroup correspond à un groupe de champ
Un FormGroup est un objet qui correspond à un groupe de champ. Notre Reactive Form a besoin
d'un FormGroup pour fonctionner, ce FormGroup sera attaché à la balise <form> grâce à
l'attribut formGroup.
Un FormControl va correspondre à un champ et va être attaché à une balise <input>, <textarea> ou
<select> grâce à l'attribut formControlName.
Par exemple, voici ci-dessous un FormGroup correspondant à un formulaire avec les champs "email"
et "password".
Création d’un Reactive Form simple
Créons ensemble notre premier formulaire avec les Reactive Forms. Reprenons l’exemple du
formulaire avec nos trois champs : Firstname, Lastname et Age.
Tout d’abord, pour utiliser les Reactive Forms, nous devons importer le
module ReactiveFormsModule dans notre AppModule.
1. Créer un composant ReactiveForm1Component
2. Côté TypeScript du composant, nous devons créer notre FormGroup avec
trois FormControls correspondants aux champs de notre formulaire.
3. Ensuite côté HTML, nous devons attacher notre formGroup à la balise form avec la
directive [formGroup]=”formGroup”.
Puis nous devons faire le lien entre les inputs et nos FormControl en rajoutant
l’attribut formControlName=”nom_du_formcontrol”.
Enfin, nous devons ajouter l’appel de notre méthode onSubmit au sein de l’événement
ngSubmit qui va s’exécuter lors du submit du formulaire.
Nous pouvons maintenant utiliser notre premier Reactive Form et vérifier que l'on récupère bien les
valeurs de notre formulaire avec [Link].
Les Validators
Avec Angular, nous pouvons utiliser des Validators qui nous permettent de définir des règles sur nos
FormControls. Si ces règles ne sont pas respectées alors le FormControl est considéré
comme invalide.
Nous pouvons vérifier à l'état de nos FormControls grâce aux attributs valid ou invalid pour vérifier si
un FormControl est valide.
Avec les Reactive Forms, nous pouvons ajouter des Validators lorsque l’on instancie notre
FormControl.
Dans l’exemple ci-dessous, nous créons un FormControl avec le Validator required qui lève une erreur
si la valeur du FormControl est vide ou null.
Création d'un Reactive Form avec des Validators
Utilisons maintenant ces Validators dans un vrai formulaire. Prenons maintenant un formulaire pour
publier un commentaire qui ne possède qu’un seul FormControl “comment”.
Le champ “comment” est obligatoire et le commentaire doit faire au minimum 3 caractères. Pour cela
nous allons utiliser les Validators required et maxLength.
Côté HTML, nous pouvons utiliser les attributs “invalid” et hasError pour afficher un message
d’erreur à l’utilisateur.
Si le champ est invalide, nous ajoutons la classe CSS "is-invalid" pour styliser notre input en rouge. Et
nous affichons un message d’erreur qui précise quelle erreur est remontée.
<ng-container> est un élément structurel d'Angular qui n'apparaît pas dans le DOM. Il est
utilisé pour regrouper plusieurs éléments sans ajouter de balise supplémentaire dans le
HTML.
Pourquoi l'utiliser ?
Éviter d’ajouter des <div> inutiles dans le DOM.
Utiliser des directives structurelles (*ngIf, *ngFor, etc.) sur plusieurs éléments à la
fois.
Améliorer la lisibilité du code HTML.
Voici le résultat du Reactive Form avec les Validators. Vous allez voir que l'état du champ est mis à
jour lorsque l'utilisateur saisie une valeur.
Grâce aux Validators, nous pouvons définir des règles pour nos champs de formulaires. Ces
règles nous permettent de mettre en place des contrôles et d’afficher des erreurs à
l’utilisateur pour améliorer son expérience.
Améliorer l'UX avec "touched & dirty"
Dans notre dernier exemple, notre formulaire affichait directement une erreur à l’utilisateur comme
quoi son champ était incorrect.
Afin de ne pas agresser directement les yeux de notre utilisateur, il est préférable d’afficher cette
erreur qu’une fois que l’utilisateur a touché ou modifié le champ et que le champ demeure invalide.
Les FormControls nous permettent de coder cette fonctionnalité en nous fournissant les attributs
“touched” et “dirty”.
Nous allons ajouter une méthode isInvalidAndTouchedOrDirty() qui va retourner true lorsque le
FormControl est invalide ET qu’il a été touché ou modifié par l’utilisateur.
Enfin, pour gérer les cas où l'utilisateur tente de submit le formulaire sans avoir toucher les champs.
Nous allons appeler la fonction markAllAsTouched() qui va permettre de mettre en lumière tous les
champs invalides à l'utilisateur.
Voici le code TypeScript du composant pour un formulaire possédant les champs "firstname",
"lastname" et "age".
Voici le HTML :
S’abonner aux modifications avec valueChanges
Angular nous permet aussi de nous abonner aux modifications de nos FormControls ou de notre
FormGroup grâce à l’attribut valueChanges qui retourne un Observable.
Prenons un formulaire avec un champ “Price” et un champ “Quantity”. Pour aider à la saisie,
nous voulons afficher le prix total à l’utilisateur.
En Angular, on utilise Observable et subscribe pour gérer les données asynchrones, comme les
appels HTTP, les événements ou les flux de données.
Un Observable est un flux de données qui peut envoyer des valeurs au fil du temps. Il est comme
un canal de télévision qui diffuse des informations.
L’abonnement (subscribe) permet de recevoir les valeurs envoyées par un Observable.
Côté Typescript, nous allons recalculer le prix total à chaque modification du formulaire. Pour cela
nous allons utiliser l’Observable valueChanges du FormGroup.
Le prix total se met à jour automatiquement à chaque changement dans le formulaire.
Prochainement : Template-Driven Forms . . .