Introduction aux formulaires angulaires 4 rédaction de validateurs de formulaire personnalisés

Ceci est la troisième partie de la série sur la création de formes en angulaire. Dans les deux premiers tutoriels, nous avons utilisé l'approche de création de formulaires basée sur les modèles et basée sur Angular. Cependant, tout en détaillant les deux approches, il y avait quelque chose que nous n'avons pas couvert: les fonctions de validation personnalisées. Ce tutoriel couvrira tout ce que vous devez savoir sur la rédaction de validateurs personnalisés qui répondent à vos besoins..

Conditions préalables

Vous n'avez pas besoin de suivre la première ou la deuxième partie de cette série pour que la troisième partie ait un sens. Cependant, si vous êtes tout à fait novice dans Angular, rendez-vous au premier tutoriel de cette série et recommencez. 

Sinon, récupérez une copie de ce code dans notre dépôt GitHub et utilisez-la comme point de départ..  

Validateurs intégrés

Angular ne dispose pas d'une énorme bibliothèque de validateurs intégrée. Depuis Angular 4, nous avons les validateurs populaires suivants dans Angular:

  • Champs obligatoires
  • Longueur minimale
  • longueur maximale
  • modèle

Il y en a un peu plus, et vous pouvez voir la liste complète dans la documentation angulaire. 

Nous pouvons utiliser les validateurs intégrés ci-dessus de deux manières:

1. En tant que directives dans des formulaires basés sur des modèles.

2. En tant que validateurs à l’intérieur du FormControl constructeur sous forme de modèles.

name = new FormControl (", Validators.required) 

Si la syntaxe ci-dessus n'a pas de sens, suivez mes tutoriels précédents sur la création d'un formulaire d'inscription à l'aide d'une approche basée sur des modèles ou d'une approche basée sur un modèle, puis passez à l'étape suivante.!

Les validateurs de formulaire intégrés couvrent à peine tous les cas d'utilisation de validation pouvant être requis dans une application réelle. Par exemple, un formulaire d'inscription pourrait devoir vérifier si les valeurs du mot de passe et confirmer les champs de contrôle du mot de passe sont égaux et afficher un message d'erreur s'ils ne correspondent pas. Un validateur qui liste des courriels d’un domaine particulier est un autre exemple courant.. 

Voici un fait: les formulaires basés sur des modèles ne sont que des formulaires basés sur des modèles situés en dessous. Dans un formulaire basé sur un modèle, nous laissons le modèle se charger de la création du modèle. La question évidente est maintenant, comment attacher un validateur à un formulaire?

Les validateurs ne sont que des fonctions. Dans un formulaire basé sur un modèle, attacher des validateurs à FormControl est simple. Dans un formulaire basé sur des modèles, cependant, il reste un peu de travail à faire. En plus de la fonction validateur, vous devrez écrire une directive pour le validateur et créer des instances de la directive dans le modèle..

Plonger dans les détails

Bien que cela ait déjà été couvert, nous allons récapituler rapidement le code du formulaire d'inscription. Tout d'abord, voici l'approche réactive.

app / signup-form / signup-form.component.ts

 // Utilisez le formbuilder pour construire le modèle de formulaire this.signupForm = this.fb.group (email: [", [Validators.required, Validators.pattern ('a-z0-9 ._% + -] + @ [a-z0-9 .-] + \. [az] 2,3 $ ')], mot de passe: this.fb.group (pwd: [", [Validators.required, Validators.minLength (8 )]], confirmPwd: [", [Validators.required, Validators.minLength (8)]], validator: PasswordMatch), genre: [", Validators.required],)

FormBuilder est un sucre de syntaxe qui crée le FormGroup et FormControl les instances. UNE FormControl suit la valeur et l'état de validation d'un élément de formulaire individuel. UNE FormGroup, d'autre part, comprend un groupe de FormControl instances, et il suit la valeur et la validité de l'ensemble du groupe.

Voici la structure que nous avons suivie:

FormGroup -> 'signupForm' FormControl -> 'email' FormGroup -> 'mot de passe' FormControl -> 'pwd' FormControl -> 'confirmPwd' FormControl -> 'genre' 

Selon les besoins, nous pouvons attacher un validateur à un FormControl ou un FormGroup. Un validateur de liste noire d’e-mail exigerait qu’il soit attaché au FormControl exemple de l'email. 

Cependant, pour les validations plus complexes où plusieurs champs de contrôle doivent être comparés et validés, il est préférable d'ajouter la logique de validation au parent. FormGroup. Comme vous pouvez le voir, mot de passe a un FormGroup son propre, et cela nous permet d'écrire facilement des validateurs qui vérifient l'égalité des pwd et confirmPwd.

Pour le formulaire piloté par les modèles, toute cette logique est intégrée au modèle HTML. Voici un exemple:

app / signup-form / signup-form.component.html

ngModel crée une instance de FormControl et le lie à un élément de contrôle de formulaire. De même, ngModelGroup crée et lie un FormGroup exemple à un élément DOM. Ils partagent la même structure de domaine modèle discutée ci-dessus. 

Il est également intéressant de noter que FormControl, FormGroup, et FormArray étendre le AbstractControl classe. Cela signifie que le AbstractControl La classe est responsable du suivi des valeurs des objets de formulaire, de leur validation et de l'activation d'autres méthodes telles que les méthodes vierges, sales et touchées.. 

Maintenant que nous connaissons les deux techniques de formulaire, écrivons notre premier validateur personnalisé.

Fonction de validation personnalisée pour les formulaires dirigés par un modèle

Les validateurs sont des fonctions qui prennent une FormControl/FormGroup par exemple en entrée et retour soit nul ou un objet d'erreur. nul est renvoyé lorsque la validation est réussie et sinon, l'objet d'erreur est renvoyé. Voici une version très basique d'une fonction de validation. 

app / password-match.ts

import FormGroup from '@ angular / forms'; fonction d'exportation passwordMatch (control: FormGroup): [key: string]: boolean 

J'ai déclaré une fonction qui accepte une instance de FormGroup en tant qu'entrée. Il renvoie un objet avec une clé de type chaîne et une valeur true / false. C'est pour que nous puissions retourner un objet d'erreur du formulaire ci-dessous:

mismatch: true

Ensuite, nous devons obtenir la valeur de la pwd et confirmPwd Instances de FormControl. Je vais utiliser control.get () chercher leurs valeurs. 

fonction d'exportation passwordMatch (control: FormGroup): [clé: chaîne de caractères]: boolean // Grab pwd et confirmPwd à l'aide de control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd');  

Nous devons maintenant faire la comparaison, puis renvoyer NULL ou un objet d'erreur..

app / password-match.ts

import AbstractControl à partir de '@ angular / forms'; fonction d'exportation passwordMatch (control: AbstractControl): [clé: chaîne de caractères]: boolean // Saisir un mot de passe et confirmer un mot de passe à l'aide de control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Si les objets FormControl n'existent pas, retourne null si (! Pwd ||! ConfirmPwd) return null; // S'ils sont bien égaux, renvoie null si (pwd.value === confirmPwd.value) return null;  // Sinon return false return mismatch: true;  

Pourquoi ai-je remplacé FormGroup avec AbstractControl? comme vous le savez, AbstractControl est la mère de toutes les classes de formulaire * et vous donne plus de contrôle sur les objets de contrôle de formulaire. Cela a l'avantage supplémentaire de rendre notre code de validation plus cohérent.

Importer le passwordMatch fonctionner dans le SignupForm composant et le déclarer comme un validateur pour le mot de passe FormGroup exemple.

app / password-match.ts

import passwordMatch de './… / password-match';… la classe d'exportation SignupFormComponent implémente OnInit ngOnInit () // Utilisez le formbuilder pour créer le modèle de formulaire this.signupForm = this.fb.group (… mot_de_passe: this.fb.group (pwd: [", [Validators.required, Validators.minLength (8)]], confirmPwd: [", [Validators.required, Validators.minLength (8)]],: validator: passwordMatch ),…) 

Affichage des erreurs

Si vous avez tout fait correctement, password.errors? .mismatch sera vrai chaque fois que les valeurs des deux champs ne correspondent pas.

password.errors? .mismatch json

Bien qu'il existe d'autres moyens d'afficher les erreurs, je vais utiliser le ngIf directive pour déterminer si un message d'erreur doit être affiché ou non.

Tout d'abord, je vais utiliser ngIf pour voir si le mot de passe est invalide. 

  

Nous utilisons mot de passe.touched pour s'assurer que l'utilisateur ne reçoit pas d'erreurs avant même d'appuyer sur une touche.

Ensuite, je vais utiliser la syntaxe ngIf = "expression; puis a else b" pour afficher la bonne erreur..

app / signup-form / signup-form.component.html

    Le mot de passe ne correspond pas   Le mot de passe doit comporter plus de 8 caractères. 

Voilà, un modèle de travail du validateur qui vérifie l’égalité des mots de passe.

Démo pour les validateurs personnalisés dans les formulaires dirigés par un modèle

Directive de validation personnalisée pour les formulaires basés sur des modèles

Nous utiliserons la même fonction de validation que nous avons créée précédemment pour le formulaire piloté par le modèle. Cependant, nous n’avons pas un accès direct aux instances de FormControl/FormGroup sous forme de gabarit. Voici ce que vous devrez faire pour que le validateur fonctionne:

  1. Créer un PasswordMatchDirective qui sert d’emballage autour du passwordMatch fonction de validation. Nous enregistrerons la directive en tant que validateur en utilisant le NG_VALIDATORS fournisseur. Plus sur cela plus tard.
  2. Attachez la directive au contrôle de formulaire de modèle. 

Écrivons d'abord la directive. Voici à quoi ressemble une directive dans Angular:

app / password-match.ts

import AbstractControl à partir de '@ angular / forms'; fonction d'exportation passwordMatch (control: AbstractControl): [clé: chaîne de caractères]: boolean // Saisir un mot de passe et confirmer un mot de passe à l'aide de control.get const pwd = control.get ('pwd'); const confirmPwd = control.get ('confirmPwd'); // Si les objets FormControl n'existent pas, retourne null si (! Pwd ||! ConfirmPwd) return null; // S'ils sont bien égaux, renvoie null si (pwd.value === confirmPwd.value) return null;  // Sinon return false return mismatch: true;  // PasswordMatchDirective @Directive (sélecteur: ", fournisseurs: []) classe d'exportation PasswordMatchDirective 

le @Directif décorator est utilisé pour marquer la classe en tant que directive angulaire. Il accepte un objet en tant qu'argument spécifiant les métadonnées de configuration de la directive, telles que les sélecteurs auxquels la directive doit être attachée, et la liste des fournisseurs à injecter, etc. Remplissons les métadonnées de la directive:

app / password-match.ts

@Directive (sélecteur: '[passwordMatch] [ngModelGroup]', // 1 fournisseurs: [// 2 fournir: NG_VALIDATORS, useValue: passwordMatch, multi: true]) classe d'exportation PasswordMatchDirective 
  1. La directive est maintenant attachée à tous les contrôles d'entrée ayant les attributs ngModelGroup et passwordMatch
  2. Nous étendons les validateurs intégrés en utilisant le NG_VALIDATORS fournisseur. Comme mentionné précédemment, NG_VALIDATORS est un fournisseur qui possède une collection extensible de validateurs. le passwordMatch La fonction que nous avons créée précédemment est déclarée en tant que dépendance. le multi: vrai définit ce fournisseur pour être un multi-fournisseur. Cela signifie que nous allons ajouter à la collection existante de validateurs fournie par NG_VALIDATORS.

Maintenant, ajoutez la directive au tableau de déclarations dans ngModule.

app / app.module.ts

… Importer PasswordMatchDirective de './password-match'; @NgModule (declarations: [AppComponent, SignupFormComponent, PasswordMatchDirective], importations: [BrowserModule, FormsModule], fournisseurs: [], bootstrap: [AppComponent]) classe d'exportation AppModule . 

Affichage des messages d'erreur

Pour afficher les messages d'erreur de validation, je vais utiliser le même modèle que nous avons créé pour les formulaires dirigés par un modèle..

 
Le mot de passe ne correspond pas Le mot de passe doit comporter plus de 8 caractères.

Conclusion

Dans ce tutoriel, nous avons appris à créer des validateurs angulaires personnalisés pour les formulaires en mode angulaire.. 

Les validateurs sont des fonctions qui renvoient null ou un objet d'erreur. Dans les formulaires dirigés par un modèle, nous devons associer le validateur à une instance FormControl / FormGroup, et c'est tout. La procédure était un peu plus complexe dans un formulaire basé sur des modèles car nous devions créer une directive par-dessus la fonction de validation.. 

Si vous souhaitez continuer à en apprendre davantage sur JavaScript, n'oubliez pas de consulter ce que nous avons dans le marché Envato..

J'espère que vous avez apprécié cette série sur Forms in Angular. Je serais ravi d'entendre vos pensées. Partagez-les à travers les commentaires.