Retour aux articles

Construire des formulaires réactifs dynamiques avec Angular 17+ et la validation personnalisée

Construire des formulaires réactifs dynamiques avec Angular 17+ et la validation personnalisée | Laty Gueye Samba - Développeur Full Stack Dakar Sénégal, Expert Java Spring Boot Angular
```html

Construire des formulaires réactifs dynamiques avec Angular 17+ et la validation personnalisée

Les formulaires réactifs avec Angular 17+ permettent de gérer efficacement des interfaces dynamiques, où la structure des champs peut évoluer et où la validation peut s’adapter au contexte métier. Cet article décrit une approche moderne, robuste et maintenable, basée sur Reactive Forms, les formulaires typés et des validateurs personnalisés.

Pourquoi les formulaires réactifs pour des besoins dynamiques ?

Un formulaire dynamique nécessite généralement : l’ajout/suppression de champs, la validation conditionnelle, la gestion de groupes et de tableaux, ainsi que des règles métier qui changent selon d’autres valeurs du formulaire.

Angular Reactive Forms répond à ces contraintes via des primitives comme : FormGroup, FormControl, FormArray et la composition de validateurs.

Préparation : configurer un formulaire typé

Les formulaires typés (introduits pour améliorer la sécurité à la compilation) réduisent les erreurs et clarifient les types attendus. L’exemple ci-dessous illustre un formulaire avec un groupe principal et un tableau dynamique.

Exemple de modèle : profil et liste d’adresses

('', { nonNullable: true, validators: [Validators.required] }), email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }), addresses: new FormArray>([]) // remplace par un typage plus strict selon le besoin }); ]]>

Créer des champs dynamiques avec FormArray

Lorsqu’un formulaire contient une liste de blocs répétés (adresses, lignes de commande, compétences, etc.), FormArray permet de créer et retirer des éléments à l’exécution.

Ajout et suppression d’éléments

('', { nonNullable: true, validators: [Validators.required] }), street: new FormControl('', { nonNullable: true, validators: [Validators.required] }), }); } const addressesArray = profileForm.controls.addresses as FormArray; function addAddress() { addressesArray.push(createAddressGroup()); } function removeAddress(index: number) { addressesArray.removeAt(index); } ]]>

Validation personnalisée : concevoir des validateurs réutilisables

Une validation personnalisée est idéale pour des règles métier spécifiques : contrôles d’unicité, contraintes inter-champs, formats propriétaires, ou encore une validation dépendante du contexte.

Validation de format : exemple “code postal”

Cet exemple propose un validateur qui vérifie un format de code postal inspiré par une règle : exactement 5 chiffres.

{ const value = String(control.value ?? ''); const isValid = /^\d{5}$/.test(value); return value.length === 0 || isValid ? null : { postalCode: { value } }; }; } ]]>

Validation inter-champs : cohérence entre deux valeurs

Une règle courante consiste à vérifier qu’un champ reste cohérent avec un autre (ex. : “confirmation mot de passe” doit correspondre au “mot de passe”).

{ const leftControl = group.get(leftKey); const rightControl = group.get(rightKey); if (!leftControl || !rightControl) return null; const leftValue = leftControl.value; const rightValue = rightControl.value; if (leftValue === rightValue) return null; return { fieldsMismatch: { leftKey, rightKey, leftValue, rightValue } }; }; } ]]>

Validation conditionnelle selon l’état du formulaire

Les formulaires dynamiques exigent souvent que les validateurs changent en fonction d’autres valeurs. Pour cela, les validateurs peuvent être ajoutés ou retirés lors de changements de contrôles.

Exemple : champ “raison sociale” requis si “type” vaut “Entreprise”

('Personne', { nonNullable: true }); const companyReasonControl = new FormControl('', { nonNullable: true }); typeControl.valueChanges.subscribe((type) => { if (type === 'Entreprise') { companyReasonControl.addValidators([Validators.required]); } else { companyReasonControl.clearValidators(); } companyReasonControl.updateValueAndValidity(); }); ]]>

Exemple complet : Angular 17+ avec Reactive Forms et validation personnalisée

L’exemple ci-dessous montre un formulaire minimal avec : validation requise, validateurs natifs et un validateur personnalisé.

Modèle et initialisation

('', { nonNullable: true, validators: [Validators.required] }), email: new FormControl('', { nonNullable: true, validators: [Validators.required, Validators.email] }), postalCode: new FormControl('', { nonNullable: true, validators: [postalCodeValidator()] }), addresses: new FormArray>([]), }); addAddress() { (this.form.controls.addresses as FormArray).push(new FormGroup({ label: new FormControl('', { nonNullable: true, validators: [Validators.required] }), street: new FormControl('', { nonNullable: true, validators: [Validators.required] }), })); } removeAddress(index: number) { (this.form.controls.addresses as FormArray).removeAt(index); } } ]]>

Template : affichage des erreurs et champs dynamiques

Le nom complet est requis.

Le format de l'email est invalide.

Le code postal doit contenir exactement 5 chiffres.


]]>

Bonnes pratiques pour des formulaires dynamiques maintenables

  • Centraliser la logique : les validateurs personnalisés doivent être factorisés dans des fonctions réutilisables.
  • Éviter les effets de bord : ne modifier les validateurs qu’au moment opportun (dans des abonnements ou méthodes dédiées).
  • Gérer l’état d’interaction : utiliser touched ou dirty pour afficher les erreurs de manière cohérente.
  • Préférer la composition : combiner plusieurs validateurs plutôt que réécrire toute la logique dans un seul validateur.
  • Typage et cohérence : utiliser les formulaires typés pour limiter les erreurs de mapping.

Conclusion

Angular 17+ fournit une base solide pour construire des formulaires réactifs dynamiques : la combinaison de FormArray, d’une gestion rigoureuse des validateurs et de règles métier spécialisées via validation personnalisée permet de produire des interfaces robustes et évolutives.

Rappel : des validateurs bien conçus et factorisés rendent le code plus lisible, testable et scalable.

À propos de l'auteur

Laty Gueye Samba est développeur Full Stack basé à Dakar, Sénégal. Spécialiste des écosystèmes Java / Spring Boot et Angular.

Contact : latygueyesamba@gmail.com  |  Dakar, Sénégal