Formulaires > Validation de formulaire

Références

L'actualité

Librairie

L'information

Validation de formulaire

Améliorez la qualité globale des données en validant la saisie de l'utilisateur pour en assurer l'exactitude et l'exhaustivité.

Cette page explique comment valider les entrées utilisateur dans l'interface utilisateur et afficher des messages de validation utiles à l'aide de formulaires réactifs et de modèles. Il suppose des connaissances de base des deux modules de formulaire.

Validation par modèle

Pour ajouter une validation à un formulaire basé sur un modèle, vous ajoutez les mêmes attributs de validation que vous le feriez avec la validation de formulaire HTML natif. Angular utilise des directives pour faire correspondre ces attributs aux fonctions de validation du framework.

Angular exécute la validation chaque fois que la valeur d'un contrôle de formulaire est modifiée et génère soit une liste d'erreurs de validation, ce qui donne un statut INVALID, soit la valeur null, qui donne un statut VALID.

Vous pouvez ensuite inspecter l'état du contrôle en exportant vers ngModel une variable de modèle locale. L'exemple suivant exporte dans NgModel une variable appelée name :

Notez les points suivants :

  • L'élément ‹input› porte les attributs de validation HTML : required et minlength. Il porte également une directive validateur personnalisé, forbiddenName.
  • #name="ngModel" exporte NgModel dans une variable locale appelée name. NgModel reflète de nombreuses propriétés de son instance FormControl sous-jacente, vous pouvez donc l'utiliser dans le modèle pour vérifier les états de contrôle tels que valid et dirty.
  • Le *ngIf sur l'élément ‹div› révèle un ensemble de messages divs imbriqués, mais uniquement si le name est invalide et que le contrôle est dirty ou touched.
  • Chaque ‹div› imbriqué peut présenter un message personnalisé pour l'une des erreurs de validation possibles. Il y a des messages pour required, minlength et forbiddenName.
Vous ne souhaitez peut-être pas que votre application affiche des erreurs avant que l'utilisateur n'ait la possibilité de modifier le formulaire. Les vérifications dirty et touched empêcher les erreurs de s'afficher jusqu'à ce que l'utilisateur fasse l'une des deux choses suivantes : modifie la valeur en rendant le contrôle sale; ou rend flou l'élément de contrôle de formulaire, en définissant le contrôle sur touché.

Validation de formulaire réactif

Dans une forme réactive, la source de la vérité est la classe de composants. Au lieu d'ajouter des validateurs via des attributs dans le modèle, vous ajoutez des fonctions de validation directement au modèle de contrôle de formulaire dans la classe de composant. Angular appelle ensuite ces fonctions chaque fois que la valeur du contrôle change.

Fonctions de validation

Il existe deux types de fonctions de validation: les validateurs de synchronisation et les validateurs asynchrones.

  • Validateurs de synchronisation : fonctions qui prennent une instance de contrôle et renvoient immédiatement un ensemble d'erreurs de validation ou null. Vous pouvez les passer comme deuxième argument lorsque vous instanciez un FormControl.
  • Validateurs asynchrones : fonctions qui prennent une instance de contrôle et renvoient une promesse ou un observable qui émet ultérieurement un ensemble d'erreurs de validation ou null. Vous pouvez les passer comme troisième argument lorsque vous instanciez un FormControl.

Pour des raisons de performances, Angular n'exécute les validateurs asynchrones que si tous les validateurs de synchronisation passent. Chacun doit être terminé avant que les erreurs ne soient définies.

Validateurs intégrés

Vous pouvez choisir d'écrire vos propres fonctions de validation ou utiliser certains des validateurs intégrés à Angular.

Les mêmes validateurs intégrés qui sont disponibles en tant qu'attributs dans des formulaires basés sur des modèles, tels que required et minlength, sont tous disponibles pour être utilisés en tant que fonctions de la classe Validators.

Pour mettre à jour le formulaire Hero afin qu'il devienne un formulaire réactif, vous pouvez utiliser certains des mêmes validateurs intégrés cette fois, sous la forme d'une fonction. Voir ci-dessous :

Notez que:
  • Le contrôle du nom met en place deux haut-validators. Validators.required et Validators.minLength(4) et un validateur personnalisé, forbiddenNameValidator.
  • Comme ces validateurs sont tous des validateurs de synchronisation, vous les transmettez comme second argument.
  • Soutenir plusieurs validateurs en transmettant les fonctions sous forme de tableau.
  • Cet exemple ajoute quelques méthodes getter. Dans un formulaire réactif, vous pouvez toujours accéder à tout contrôle de formulaire via la méthode get sur son groupe parent, mais il est parfois utile de définir des getter en tant que raccourcis du modèle.

Si vous examinez à nouveau le modèle pour la saisie du nom, celui-ci est assez similaire à l'exemple basé sur un modèle.

Points clés:

  • Le formulaire n'exporte plus aucune directive et utilise à la place le name getter défini dans la classe de composant.
  • L'attribut required est toujours présent. Bien que cela ne soit pas nécessaire à des fins de validation, vous pouvez le conserver dans votre modèle pour des raisons de style CSS ou d'accessibilité.

Validateurs personnalisés

Étant donné que les validateurs intégrés ne correspondent pas toujours au cas d'utilisation exact de votre application, vous souhaiterez parfois créer un validateur personnalisé. Examinez la fonction forbiddenNameValidator des exemples précédents de ce guide. Voici à quoi ressemble la définition de cette fonction:
La fonction est en réalité une fabrique qui utilise une expression régulière pour détecter un nom spécifique interdit et renvoie une fonction de validation.

Dans cet exemple, le nom interdit est "bob", ainsi le validateur rejettera tout nom de hero contenant "bob". Ailleurs, il pourrait rejeter "alice" ou tout nom associé à l'expression régulière de configuration.

L'usine forbiddenNameValidator renvoie la fonction de validation configurée. Cette fonction prend un objet de commande Angular et renvoie soit null si la valeur de contrôle est valable ou un objet d'erreur de validation. L'objet d'erreur de validation a généralement une propriété dont le nom est la clé de validation 'forbiddenName' et dont la valeur est un dictionnaire arbitraire de valeurs que vous pouvez insérer dans un message d'erreur {name}.

Les validateurs asynchrones personnalisés sont similaires aux validateurs de synchronisation, mais ils doivent plutôt renvoyer une promesse ou un observable qui émet ultérieurement une valeur null ou un objet d'erreur de validation. Dans le cas d'un observable, celui-ci doit être complété, le formulaire utilise alors la dernière valeur émise pour validation.

Ajout aux formes réactives

Dans les formulaires réactifs, les validateurs personnalisés sont assez simples à ajouter. Tout ce que vous avez à faire est de passer la fonction directement au FormControl.

Ajout à des formulaires basés sur des modèles

Dans les formulaires basés sur des modèles, vous n'avez pas d'accès direct à l'instance FormControl, vous ne pouvez donc pas transmettre le validateur comme vous le pouvez pour les formulaires réactifs. Au lieu de cela, vous devez ajouter une directive au modèle.

Le correspondant ForbiddenValidatorDirective sert de wrapper autour du forbiddenNameValidator.

Angular reconnaît le rôle de la directive dans le processus de validation car celle-ci s'enregistre auprès du fournisseur NG_VALIDATORS, un fournisseur avec une collection extensible de validateurs.

La classe de directive implémente ensuite l'interface Validator, de sorte qu'elle puisse facilement s'intégrer aux formes Angular. Voici le reste de la directive pour vous aider à avoir une idée de la façon dont tout cela se passe :

Une fois que le ForbiddenValidatorDirective est prêt, vous pouvez simplement ajouter son sélecteur appForbiddenName, à n'importe quel élément d'entrée pour l'activer. Par exemple:

Vous avez peut-être remarqué que la directive de validation personnalisée est instanciée avec useExisting plutôt que useClass. Le validateur inscrit doit être cette instance de ForbiddenValidatorDirective, l'instance du formulaire avec sa propriété forbiddenName liée à "bob". Si vous deviez remplacer useExisting par useClass, vous enregistrez une nouvelle instance de classe, qui ne possède pas forbiddenName.

Statut des classes de contrôle CSS

Comme dans AngularJS, Angular reflète automatiquement de nombreuses propriétés de contrôle sur l'élément de contrôle de formulaire sous forme de classes CSS. Vous pouvez utiliser ces classes pour styler les éléments de contrôle de formulaire en fonction de l'état du formulaire. Les classes suivantes sont actuellement supportées :

  • .ng-valid
  • .ng-invalid
  • .ng-pending
  • .ng-pristine
  • .ng-dirty
  • .ng-untouched
  • .ng-touched

La forme du hero utilise les classes .ng-valid et .ng-invalid pour définir la couleur de la bordure de chaque contrôle de formulaire.


Validation inter-champs

Cette section montre comment effectuer une validation entre champs. Cela suppose des connaissances de base sur la création de validateurs personnalisés.

Si vous n'avez pas créé de validateurs personnalisés auparavant, commencez par consulter la section des validateurs personnalisés.

Dans la section suivante, nous veillerons à ce que nos héros ne révèlent pas leur véritable identité en remplissant le formulaire Héros. Nous ferons cela en validant que les noms de héros et les AlterEgo ne correspondent pas.

Ajout aux formes réactives

Le formulaire a la structure suivante :
Notez que le name et alterEgo sont des contrôles frères. Pour évaluer les deux contrôles dans un seul validateur personnalisé, nous devons effectuer la validation dans un contrôle ancêtre commun: le FormGroup. De cette façon, nous pouvons interroger les contrôles FormGroup enfants pour nous permettre de comparer leurs valeurs.

Pour ajouter un validateur à la FormGroup, passez le nouveau validateur comme deuxième argument lors de la création.

Le code du validateur est le suivant :

Le validateur d'identité implémente l'interface ValidatorFn. Il prend un objet de contrôle Angular en tant qu'argument et renvoie null si le formulaire est valide ou autrement ValidationErrors.

D'abord, nous récupérons les contrôles enfants en appelant la méthode get() du FormGroups. Ensuite, nous comparons simplement les valeurs des contrôles name et alterEgo.

Si les valeurs ne correspondent pas, l'identité du héros reste secrète et nous pouvons renvoyer null en toute sécurité. Sinon, l'identité du héros est révélée et nous devons marquer le formulaire comme invalide en renvoyant un objet d'erreur.

Ensuite, pour offrir une meilleure expérience utilisateur, nous affichons un message d'erreur approprié lorsque le formulaire est invalide.

Notez que nous vérifions si :

  • le FormGroup a l'erreur de validation croisée renvoyée par le validateur identityRevealed,
  • l'utilisateur doit encore interagir avec le formulaire.

Ajout aux formulaires basés sur des modèles

Nous devons d'abord créer une directive qui encapsulera la fonction de validation. Nous le fournissons en tant que validateur utilisant le jeton NG_VALIDATORS. Si vous ne savez pas pourquoi ou si vous ne comprenez pas bien la syntaxe, consultez la section précédente.

Ensuite, nous devons ajouter la directive au modèle html. Comme le validateur doit être enregistré au plus haut niveau du formulaire, nous mettons la directive sur la formbalise.

Pour offrir une meilleure expérience utilisateur, nous affichons un message d'erreur approprié lorsque le formulaire n'est pas valide.

Notez que nous vérifions si :
  • le formulaire a l'erreur de validation croisée renvoyée par le validateur identityRevealed,
  • l'utilisateur doit encore interagir avec le formulaire.
Ceci termine l'exemple de validation croisée. Nous avons réussi à:
  • valider le formulaire en fonction des valeurs de deux contrôles frères,
  • affiche un message d'erreur descriptif après que l'utilisateur a interagi avec le formulaire et que la validation a échoué.


Validation Async

Cette section montre comment créer des validateurs asynchrones. Cela suppose des connaissances de base sur la création de validateurs personnalisés .

Les bases

Tout comme les validateurs synchrones ont les interfaces ValidatorFn et Validator, les validateurs asynchrones ont leurs propres contreparties: AsyncValidatorFn et AsyncValidator.

Ils sont très similaires avec la seule différence:

Ils doivent retourner une promesse ou un observable, L'observable renvoyé doit être fini, ce qui signifie qu'il doit être terminé à un moment donné. Pour convertir un infini observable en un fini, le pipe observable par un opérateur de filtrage tel que first, last, take, ou takeUntil. Il est important de noter que la validation asynchrone a lieu après la validation synchrone et qu'elle est effectuée uniquement si la validation synchrone est réussie. Cette vérification permet aux formulaires d'éviter des processus de validation asynchrone potentiellement coûteux, tels qu'une demande HTTP, si plusieurs méthodes de validation élémentaires échouent.

Une fois que la validation asynchrone a commencé, le contrôle de formulaire entre dans un état pending. Vous pouvez inspecter la propriété pending du contrôle et l'utiliser pour donner un retour visuel sur la validation en cours.

Un schéma d'interface utilisateur courant consiste à afficher un compteur pendant la validation async. L'exemple suivant montre comment y parvenir à l'aide de formulaires basés sur des modèles:


Implémentation du validateur async personnalisé

Dans la section suivante, la validation est effectuée de manière asynchrone pour garantir que nos héros choisissent un AlterEgo qui n'est pas déjà pris. De nouveaux héros s'enrôlent constamment et de vieux héros quittent le service. Cela signifie que nous n'avons pas la liste des AlterEgo disponibles à l'avance.

Pour valider l'AlterEgo potentiel, nous devons consulter une base de données centrale de tous les héros actuellement enrôlés. Le processus est asynchrone, nous avons donc besoin d'un validateur spécial pour cela.

Commençons par créer la classe validateur.

Comme vous pouvez le constater, la classe UniqueAlterEgoValidator implémente l'interface AsyncValidator. Dans le constructeur, nous injectons le HeroesService qui a l'interface suivante :

Dans une application du monde réel, HeroesService est chargé d'envoyer une requête HTTP à la base de données Hero pour vérifier si l'AlterEgo est disponible. Du point de vue du validateur, l'implémentation réelle du service n'est pas importante, nous pouvons donc simplement coder par rapport à HeroesServiceinterface.

La méthode isAlterEgoTaken() distribue une requête HTTP qui vérifie si l'AlterEgo est disponible et renvoie Observable ‹boolean› le résultat. Nous transmettons la réponse à travers l'opérateur map et la transformons en un résultat de validation. Comme toujours, nous retournons null si le formulaire est valide et ValidationErrors s'il ne l'est pas. Nous nous assurons de gérer les éventuelles erreurs avec l'opérateur catchError.

Ici, nous avons décidé que l'erreur isAlterEgoTaken() est traitée comme une validation réussie, car le fait de ne pas faire de demande de validation ne signifie pas nécessairement que l'AlterEgo est invalide. Vous pouvez gérer l'erreur différemment et renvoyer l'objet ValidationError à la place.

Après un certain temps, la chaîne observable se termine et la validation async est effectuée. L'indicateur pending est défini sur falseet la validité du formulaire est mise à jour.

Note on performance

Par défaut, tous les validateurs sont exécutés après chaque changement de valeur de formulaire. Avec les validateurs synchrones, cela n'aura probablement aucun impact notable sur les performances des applications. Cependant, il est courant que les validateurs asynchrones exécutent une sorte de requête HTTP pour valider le contrôle. L'envoi d'une requête HTTP après chaque frappe peut mettre l'API backend à rude épreuve et doit être évité si possible.

Nous pouvons retarder la mise à jour de la validité du formulaire en modifiant la propriété updateOn de change (valeur par défaut) en submit ou blur.

Avec des formulaires basés sur des modèles :