Aller au contenu principal

17-4 Validations

On peut créer un formulaire, renseigner les champs, le soumettre et lire les données, mais un formulaire vient généralement avec des validations. En effet, avant de créer un projet, on veut s'assurer qu'il a au minimum un nom et une description.

Valider un champ

Pour valider un champ de formulaire, on doit premièrement définir une ou plusieurs règles de validation. Il existe plusieurs règles prédéfinies dans Angular et vous pouvez consulter la liste complète ici: https://angular.io/api/forms/Validators.

Il est évidemment possible de créer nos propres valideurs, mais ceux par défaut seront suffisants pour commencer.

Validator Required pour spécifier qu'un champ est requis

Le valideur le plus évident est Required, comme quoi un champ est requis. Pour ajouter un valideur, on passe un deuxième argument à FormControl(), soit un tableau contenant la liste des valideurs (et donc des validations à exécuter).

src/app/features/projets/pages/projet-creer.ts
export class ProjetCreer {
projetForm = new FormGroup({
nom: new FormControl('', [Validators.required]),
description: new FormControl(''),
});

//...

Validator minLength

Pour le nom du projet, au delà de vérifier que des données ont été entrées, on pourrait fournir une longueur minimale comme 3 caractères.

src/app/features/projets/pages/projet-creer.ts
export class ProjetCreer {
projetForm = new FormGroup({
nom: new FormControl('', [Validators.required, Validators.minLength(3)]),
description: new FormControl(''),
});

//...
attention

Le fait de mettre des valideurs n'empêche pas de soumettre le formulaire, mais nous permets de vérifier si le formulaire est valide ou non avant d'en faire l'envoi, ou encore d'afficher des messages à l'utilisateur.

Nous verrons un peu plus loin comment traiter la soumission du formulaire.

Afficher les erreurs de validation

Utilisation de getters pour les champs

Pour accéder aux champs à partir du template, il faut accéder au formulaire. Pour cela, on peut faire des getters/setters, ce qui simplifiera grandement l'accès aux valeurs derrière les champs.

Ajoutez les getters/setters suivants pour rendre disponibles au template les champs de formulaire:

src/app/features/projets/pages/projet-creer.ts
export class ProjetCreer {
projetForm = new FormGroup({
nom: new FormControl(''),
description: new FormControl(''),
});

get nom() {
return this.projetForm.get('nom');
}

get description() {
return this.projetForm.get('description')
}

protected soumettre() {
let nom = this.nom?.value;
console.log(nom);
}
}

Afficher les erreurs

Pour afficher un message d'erreur, on peut utiliser un div avec la classe invalid-feedback. En effet, cette classe CSS applique un style de message d'erreur au texte. Il s'agit d'une classe propre à Bootstrap et il est important de la mettre après le champ/label.

src/app/features/projets/pages/projet-creer.ts
@Component({
selector: 'app-projet-creer',
imports: [
ReactiveFormsModule
],
template: `
<div class="row">
<div class="col-lg-6 offset-lg-3">
<h1>Créer un nouveau projet</h1>

<form [formGroup]="projetForm" (ngSubmit)="soumettre()">
<div class="form-floating mb-3">
<input type="text" formControlName="nom" class="form-control" id="projetNom" placeholder="Nom">
<label for="projetNom">Nom</label>
<div class="invalid-feedback">
@if(nom?.errors?.['required']) {
<span>
Veuillez entrer un nom pour le projet
</span>
}
</div>
</div>

<div class="form-floating mb-3">
<textarea class="form-control" formControlName="description" placeholder="Description" id="projetDescription"></textarea>
<label for="projetDescription">Description</label>
</div>

<button type="submit" class="btn btn-primary">Soumettre</button>
</form>
</div>
</div>
`,
styles: ``
})
info

@if("nom?.errors?.['required']") affiche conditionnellement le message, tout dépendant de si le champ nom contient une erreur de type required.

Classe CSS is-invalid

Malheureusement, cela n'affiche toujours pas de message. La raison est que le bloc invalid-feedback est seulement affiché dans le cas où la classe CSS is-invalid est présente sur le champ. Encore là, il s'agit d'une mécanique propre à Bootstrap.

On peut ajouter de façon conditionnelle cette classe au niveau du champ de la façon suivante:

src/app/pages/projets/projet-creer.page.ts
@Component({
selector: 'app-projet-creer',
imports: [
ReactiveFormsModule
],
template: `
<div class="row">
<div class="col-lg-6 offset-lg-3">
<h1>Créer un nouveau projet</h1>

<form [formGroup]="projetForm" (ngSubmit)="soumettre()">
<div class="form-floating mb-3">
<input type="text" formControlName="nom"
class="form-control"
id="projetNom" placeholder="Nom"
[class.is-invalid]="nom?.invalid">
<label for="projetNom">Nom</label>
<div class="invalid-feedback">
@if(nom?.errors?.['required']) {
<span>
Veuillez entrer un nom pour le projet
</span>
}
</div>
</div>

<div class="form-floating mb-3">
<textarea class="form-control" formControlName="description" placeholder="Description" id="projetDescription"></textarea>
<label for="projetDescription">Description</label>
</div>

<button type="submit" class="btn btn-primary">Soumettre</button>
</form>
</div>
</div>
`,
styles: ``
})
info
  • [class.is-invalid] est une directive Angular permettant d'ajouter ou non une classe (is-invalid ici), tout dépendant d'une condition, soit la portion de droite de l'expression.
  • [class.is-invalid]="nom?.invalid" applique la classe CSS is-invalid si la propriété nom est invalide.

Maintenant, le message s'affiche!

http://localhost:4200

Afficher le message d'erreur suite à l'entrée de données

Le message est constamment affiché, même si vous n'avez pas encore touché au formulaire. C'est un peu étrange qu'un formulaire vous soit présenté en mode erreur avant même que vous ayez interagi avec ce dernier.

Pour pallier à ce problème, on peut modifier la condition d'affichage de la classe CSS is-invalid pour inclure deux conditions supplémentaires:

src/app/pages/projets/projet-creer.page.ts
<input type="text" formControlName="nom"
class="form-control"
id="projetNom" placeholder="Nom"
[class.is-invalid]="nom?.invalid && (nom?.dirty || nom?.touched)">
danger

WebStorm affichera en rouge la propriété touched, mais c'est un bogue de WebStorm. Vous pouvez ignorer, l'application compile et s'exécute correctement.

info

dirty veut dire que le champ a été modifié. touched veut dire que l'utilisateur a interagi avec le champ.

De cette façon, on présente l'erreur seulement si l'utilisateur a interagi avec le champ ou que ce dernier a été modifié d'une quelconque façon.

Afficher plus d'un message d'erreur

Le champ nom contient deux valideurs: required et minlength. Pour afficher plus d'un message, on n'a qu'à ajouter une condition supplémentaire dans la liste des messages d'erreur invalid-feedback via l'utilisation de @if.

src/app/features/projets/pages/projet-creer.ts
<!-- ... -->
<div class="form-floating mb-3">
<input type="text" formControlName="nom"
class="form-control"
id="projetNom" placeholder="Nom"
[class.is-invalid]="nom?.invalid && (nom?.dirty || nom?.touched)">
<label for="projetNom">Nom</label>
<div class="invalid-feedback">
@if(nom?.errors?.['required']) {
<span>
Veuillez entrer un nom pour le projet
</span>
}
@if(nom?.errors?.['minlength']) {
<span>
Le nom du projet doit contenir au minimum 3 caractères
</span>
}
</div>
</div>
<!-- ... -->
info

Un seul message d'erreur sera affiché à la fois! Ainsi, pour voir le message de longueur minimale, vous devrez entrer 1 ou 2 caractères.

Validation OnSubmit

Il est possible de passer un objet d'options au FormGroup et cet objet peut contenir une propriété updateOn qui précise à quel moment la validation doit avoir lieu.

Pour le moment, la validation a lieu dès que vous commencez à entrer des données dans le champ. Cela peut être agaçant pour un utilisateur de recevoir des messages d'erreur immédiatement alors qu'il n'a pas fini de renseigner le champ.

Il est donc possible de valider le formulaire lors de trois événements distincts:

  • change (par défaut)
  • blur lorsque l'utilisateur quitte le champ
  • submit lorsque le formulaire est envoyé

Essayons de changer pour blur:

src/app/features/projets/pages/projet-creer.ts
export class ProjetCreer {
projetForm = new FormGroup({
nom: new FormControl('', [Validators.required, Validators.minLength(3)]),
description: new FormControl(''),
}, {
updateOn : 'blur'
});

info

Observez dans le navigateur que les erreurs du champ nom sont maintenant seulement affichées lorsque vous quittez le champ nom!

Nous allons laisser le tout ainsi.