Ce tutoriel vous montre comment créer un template-driven form. Les éléments de contrôle du formulaire sont liés à des propriétés de données dotées d'une validation des saisies. La validation des saisies aide à préserver l'intégrité des données, et le style améliore l'expérience utilisateur.
Les template-driven forms utilisent le two-way binding pour mettre à jour le modèle de données du composant quand des modifications sont faites dans le template, et inversement.
Template-driven forms ou reactive forms
Angular prend en charge deux approches de conception pour les formulaires interactifs. Les template-driven forms vous permettent d'utiliser des directives spécifiques aux formulaires dans votre template Angular. Les reactive forms proposent une approche pilotée par le modèle pour construire des formulaires.
Les template-driven forms sont un excellent choix pour les formulaires petits ou simples, tandis que les reactive forms passent mieux à l'échelle et conviennent aux formulaires complexes. Pour une comparaison des deux approches, consultez Choisir une approche
Vous pouvez créer presque n'importe quel type de formulaire avec un template Angular : formulaires de connexion, formulaires de contact et à peu près tous les formulaires métier. Vous pouvez disposer les contrôles de façon créative et les lier aux données de votre modèle objet. Vous pouvez définir des règles de validation et afficher les erreurs de validation, autoriser sous condition la saisie dans certains contrôles, déclencher un retour visuel intégré, et bien plus encore.
Objectifs
Ce tutoriel vous apprend à :
- Créer un formulaire Angular avec un composant et un template
- Utiliser
ngModelpour créer des two-way bindings qui lisent et écrivent les valeurs des contrôles de saisie - Fournir un retour visuel grâce à des classes CSS spéciales qui suivent l'état des contrôles
- Afficher les erreurs de validation aux utilisateurs et autoriser sous condition la saisie dans les contrôles de formulaire selon l'état du formulaire
- Partager des informations entre éléments HTML à l'aide de variables de référence de template
Créer un template-driven form
Les template-driven forms s'appuient sur des directives définies dans le FormsModule.
| Directives | Détails |
|---|---|
NgModel |
Réconcilie les changements de valeur de l'élément de formulaire associé avec les changements du modèle de données, ce qui vous permet de répondre aux saisies de l'utilisateur avec de la validation et de la gestion d'erreurs. |
NgForm |
Crée une instance FormGroup de premier niveau et la lie à un élément <form> pour suivre la valeur agrégée du formulaire et son état de validation. Dès que vous importez FormsModule, cette directive est active par défaut sur toutes les balises <form>. Vous n'avez pas besoin d'ajouter de selector particulier. |
NgModelGroup |
Crée une instance FormGroup et la lie à un élément du DOM. |
Aperçu des étapes
Au cours de ce tutoriel, vous liez un exemple de formulaire à des données et gérez les saisies de l'utilisateur en suivant les étapes ci-dessous.
- Créez le formulaire de base.
- Définissez un exemple de modèle de données
- Incluez l'infrastructure nécessaire, comme le
FormsModule
- Liez les contrôles de formulaire aux propriétés de données à l'aide de la directive
ngModelet de la syntaxe du two-way binding. - Suivez la validité des saisies et l'état des contrôles avec
ngModel.- Ajoutez du CSS personnalisé pour fournir un retour visuel sur l'état
- Affichez et masquez les messages d'erreur de validation
- Répondez à un événement natif de clic sur un bouton HTML en ajoutant des données au modèle.
- Gérez la soumission du formulaire à l'aide de la propriété d'output
ngSubmitdu formulaire.- Désactivez le bouton Submit tant que le formulaire n'est pas valide
- Après la soumission, remplacez le formulaire terminé par un autre contenu sur la page
Créer le formulaire
L'application d'exemple fournie crée la classe
Actor, qui définit le modèle de données reflété dans le formulaire.actor.ts
export class Actor { constructor( public id: number, public name: string, public skill: string, public studio?: string, ) {} }La mise en page et les détails du formulaire sont définis dans la classe
ActorFormComponent.actor-form.component.ts (v1)
import {Component} from '@angular/core'; import {Actor} from '../actor'; import {FormsModule} from '@angular/forms'; import {JsonPipe} from '@angular/common'; @Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe], }) export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } }La valeur « app-actor-form » du
selectordu composant signifie que vous pouvez placer ce formulaire dans un template parent avec la balise<app-actor-form>.Le code suivant crée une nouvelle instance d'acteur, afin que le formulaire initial puisse afficher un exemple d'acteur.
const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn"Cette démo utilise des données factices pour
modeletskills. Dans une vraie application, vous injecteriez un service de données pour obtenir et enregistrer de vraies données, ou vous exposeriez ces propriétés sous forme d'inputs et d'outputs.Le composant active la fonctionnalité Forms en important le module
FormsModule.@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe], }) export class ActorFormComponent {Le formulaire est affiché dans la mise en page de l'application définie par le template du composant racine.
app.component.html
<app-actor-form />Le template initial définit la mise en page d'un formulaire avec deux groupes de formulaire et un bouton de soumission. Les groupes de formulaire correspondent à deux propriétés du modèle de données Actor : name et studio. Chaque groupe comporte un libellé et une zone de saisie.
- L'élément de contrôle
<input>Name possède l'attribut HTML5required - L'élément de contrôle
<input>Studio ne l'a pas, carstudioest facultatif
Le bouton Submit porte quelques classes de style. À ce stade, la mise en page du formulaire est entièrement en HTML5 pur, sans binding ni directive.
- L'élément de contrôle
L'exemple de formulaire utilise quelques classes de style de Twitter Bootstrap :
container,form-group,form-controletbtn. Pour utiliser ces styles, la feuille de style de l'application importe la library.styles.css
@import url('https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css');Le formulaire exige que la compétence d'un acteur soit choisie dans une liste prédéfinie de
skillsgérée en interne dansActorFormComponent. La boucle Angular@forparcourt les valeurs de données pour remplir l'élément<select>.actor-form.component.html (skills)
<div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div>
Si vous lancez l'application maintenant, vous voyez la liste des compétences dans le contrôle de sélection. Les éléments de saisie ne sont pas encore liés à des valeurs de données ni à des événements : ils sont donc encore vides et n'ont aucun comportement.
Lier les contrôles de saisie aux propriétés de données
L'étape suivante consiste à lier les contrôles de saisie aux propriétés Actor correspondantes avec le two-way binding, afin qu'ils répondent aux saisies de l'utilisateur en mettant à jour le modèle de données, et qu'ils répondent aussi aux changements programmatiques des données en mettant à jour l'affichage.
La directive ngModel déclarée dans le FormsModule vous permet de lier les contrôles de votre template-driven form aux propriétés de votre modèle de données.
Quand vous incluez la directive avec la syntaxe du two-way binding, [(ngModel)], Angular peut suivre la valeur du contrôle et les interactions de l'utilisateur avec celui-ci, et garder la vue synchronisée avec le model.
- Modifiez le fichier de template
actor-form.component.html. - Trouvez la balise
<input>à côté du libellé Name. - Ajoutez la directive
ngModelavec la syntaxe du two-way binding[(ngModel)]="...".
actor-form.component.html (extrait)
<input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" />
TODO: remove this: {{ model.name }}
Utile : Cet exemple comporte une interpolation de diagnostic temporaire après chaque balise input, {{model.name}}, pour afficher la valeur actuelle de la propriété correspondante. Le commentaire vous rappelle de supprimer les lignes de diagnostic quand vous avez fini d'observer le two-way binding en action.
Accéder à l'état global du formulaire
Quand vous avez importé le FormsModule dans votre composant, Angular a automatiquement créé et attaché une directive NgForm à la balise <form> du template (car NgForm a le selector form, qui correspond aux éléments <form>).
Pour accéder au NgForm et à l'état global du formulaire, déclarez une variable de référence de template.
Modifiez le fichier de template
actor-form.component.html.Ajoutez à la balise
<form>une variable de référence de template,#actorForm, et définissez sa valeur comme suit.actor-form.component.html (extrait)
<form #actorForm="ngForm">La variable de template
actorFormest désormais une référence à l'instance de la directiveNgFormqui gouverne le formulaire dans son ensemble.Lancez l'application.
Commencez à taper dans la zone de saisie Name.
À mesure que vous ajoutez et supprimez des caractères, vous les voyez apparaître et disparaître du modèle de données.
La ligne de diagnostic qui affiche les valeurs interpolées montre que les valeurs circulent réellement de la zone de saisie vers le model, et inversement.
Nommer les éléments de contrôle
Quand vous utilisez [(ngModel)] sur un élément, vous devez définir un attribut name pour cet élément.
Angular utilise le nom attribué pour enregistrer l'élément auprès de la directive NgForm attachée à l'élément <form> parent.
L'exemple a ajouté un attribut name à l'élément <input> et l'a défini à « name », ce qui est logique pour le nom de l'acteur.
N'importe quelle valeur unique convient, mais un nom descriptif est utile.
- Ajoutez des bindings
[(ngModel)]et des attributsnamesimilaires à Studio et Skill. - Vous pouvez maintenant supprimer les messages de diagnostic qui affichent les valeurs interpolées.
- Pour vérifier que le two-way binding fonctionne pour tout le modèle d'acteur, ajoutez en haut du template du composant un nouveau binding de texte avec le pipe
json, qui sérialise les données en chaîne de caractères.
Après ces modifications, le template du formulaire devrait ressembler à ceci :
actor-form.component.html (extrait)
{{ model | json }}
<div class="form-group">
<label for="name">Name</label>
<input
type="text"
class="form-control"
id="name"
required
[(ngModel)]="model.name"
name="name"
/>
</div>
<div class="form-group">
<label for="studio">Studio</label>
<input
type="text"
class="form-control"
id="studio"
[(ngModel)]="model.studio"
name="studio"
/>
</div>
<div class="form-group">
<label for="skill">Skill</label>
<select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill">
@for (skill of skills; track $index) {
<option [value]="skill">{{ skill }}</option>
}
</select>
</div>
Vous remarquerez que :
Chaque élément
<input>possède une propriétéid. Elle est utilisée par l'attributforde l'élément<label>pour associer le libellé à son contrôle de saisie. Il s'agit d'une fonctionnalité HTML standard.Chaque élément
<input>possède aussi la propriéténamerequise, qu'Angular utilise pour enregistrer le contrôle auprès du formulaire.
Une fois les effets observés, vous pouvez supprimer le binding de texte {{ model | json }}.
Suivre l'état du formulaire
Angular applique la classe ng-submitted aux éléments form une fois le formulaire soumis. Cette classe peut servir à modifier le style du formulaire après sa soumission.
Suivre l'état des contrôles
Ajouter la directive NgModel à un contrôle lui ajoute des noms de classes qui décrivent son état.
Ces classes peuvent servir à modifier le style d'un contrôle selon son état.
Le tableau suivant décrit les noms de classes qu'Angular applique selon l'état du contrôle.
| États | Classe si vrai | Classe si faux |
|---|---|---|
| Le contrôle a été visité. | ng-touched |
ng-untouched |
| La valeur du contrôle a changé. | ng-dirty |
ng-pristine |
| La valeur du contrôle est valide. | ng-valid |
ng-invalid |
Angular applique aussi la classe ng-submitted aux éléments form lors de la soumission, mais pas aux contrôles à l'intérieur de l'élément form.
Vous utilisez ces classes CSS pour définir les styles de votre contrôle selon son état.
Observer l'état des contrôles
Pour voir comment le framework ajoute et retire les classes, ouvrez les outils de développement du navigateur et inspectez l'élément <input> qui représente le nom de l'acteur.
À l'aide des outils de développement de votre navigateur, trouvez l'élément
<input>qui correspond à la zone de saisie Name. Vous pouvez voir que l'élément possède plusieurs classes CSS en plus de « form-control ».Au premier affichage, les classes indiquent que sa valeur est valide, que la valeur n'a pas été modifiée depuis l'initialisation ou la réinitialisation, et que le contrôle n'a pas été visité depuis l'initialisation ou la réinitialisation.
<input class="form-control ng-untouched ng-pristine ng-valid" />Effectuez les actions suivantes sur la zone
<input>Name et observez les classes qui apparaissent.Regardez sans toucher. Les classes indiquent qu'il est non touché, intact (pristine) et valide.
Cliquez dans la zone du nom, puis cliquez en dehors. Le contrôle a maintenant été visité, et l'élément porte la classe
ng-touchedau lieu de la classeng-untouched.Ajoutez des barres obliques à la fin du nom. Il est maintenant touché et modifié (dirty).
Effacez le nom. La valeur devient alors invalide, donc la classe
ng-invalidremplace la classeng-valid.
Créer un retour visuel pour les états
La paire ng-valid/ng-invalid est particulièrement intéressante, car vous voulez envoyer un
signal visuel fort quand les valeurs sont invalides.
Vous voulez aussi signaler les champs obligatoires.
Vous pouvez signaler à la fois les champs obligatoires et les données invalides avec une barre colorée à gauche de la zone de saisie.
Pour modifier l'apparence de cette façon, suivez les étapes ci-dessous.
Ajoutez des définitions pour les classes CSS
ng-*.Ajoutez ces définitions de classes dans un nouveau fichier
forms.css.Ajoutez le nouveau fichier au projet, au même niveau que
index.html:forms.css
.ng-valid[required], .ng-valid.required { border-left: 5px solid #42A948; /* green */ } .ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */ }Dans le fichier
index.html, modifiez la balise<head>pour inclure la nouvelle feuille de style.index.html (styles)
<link rel="stylesheet" href="assets/forms.css" />
Afficher et masquer les messages d'erreur de validation
La zone de saisie Name est obligatoire, et la vider fait passer la barre au rouge. Cela indique que quelque chose ne va pas, mais l'utilisateur ne sait pas quoi ni comment y remédier. Vous pouvez fournir un message utile en vérifiant l'état du contrôle et en y réagissant.
La liste déroulante Skill est aussi obligatoire, mais elle n'a pas besoin de ce type de gestion d'erreurs, car la liste de sélection limite déjà le choix à des valeurs valides.
Pour définir et afficher un message d'erreur au moment opportun, suivez les étapes ci-dessous.
-
Ajouter une référence locale à l'input
Ajoutez à la balise
inputune variable de référence de template qui vous permet d'accéder au contrôle Angular de la zone de saisie depuis le template. Dans l'exemple, la variable est#name="ngModel".La variable de référence de template (
#name) est définie à"ngModel", car c'est la valeur de la propriétéNgModel.exportAs. Cette propriété indique à Angular comment relier une variable de référence à une directive. -
Ajouter le message d'erreur
Ajoutez un
<div>qui contient un message d'erreur adapté. -
Rendre le message d'erreur conditionnel
Affichez ou masquez le message d'erreur en liant des propriétés du contrôle
nameà la propriétéhiddende l'élément<div>du message. -
Ajouter un message d'erreur conditionnel au nom
Ajoutez un message d'erreur conditionnel à la zone de saisie
name, comme dans l'exemple suivant.
actor-form.component.html (hidden-error-msg)
<div [hidden]="name.valid || name.pristine" class="alert alert-danger">
Illustration de l'état « pristine »
Dans cet exemple, vous masquez le message quand le contrôle est soit valide, soit intact (pristine).
Intact signifie que l'utilisateur n'a pas modifié la valeur depuis son affichage dans ce formulaire.
Si vous ignorez l'état pristine, vous ne masqueriez le message que lorsque la valeur est valide.
Si vous arrivez dans ce composant avec un nouvel acteur vierge ou un acteur invalide, vous verrez le message d'erreur immédiatement, avant même d'avoir fait quoi que ce soit.
Vous voudrez peut-être que le message ne s'affiche que lorsque l'utilisateur effectue une modification invalide.
Masquer le message tant que le contrôle est dans l'état pristine permet d'atteindre cet objectif.
Vous verrez l'importance de ce choix quand vous ajouterez un nouvel acteur au formulaire à l'étape suivante.
Ajouter un nouvel acteur
Cet exercice montre comment répondre à un événement natif de clic sur un bouton HTML en ajoutant des données au modèle. Pour permettre aux utilisateurs du formulaire d'ajouter un nouvel acteur, vous allez ajouter un bouton New Actor qui répond à un événement de clic.
Dans le template, placez un élément
<button>« New Actor » en bas du formulaire.Dans le fichier du composant, ajoutez la méthode de création d'acteur au modèle de données des acteurs.
actor-form.component.ts (méthode New Actor)
newActor() { this.model = new Actor(42, '', ''); }Liez l'événement de clic du bouton à une méthode de création d'acteur,
newActor().actor-form.component.html (bouton New Actor)
<button type="button" class="btn btn-default" (click)="newActor()">New Actor</button>Relancez l'application et cliquez sur le bouton New Actor.
Le formulaire se vide, et les barres obligatoire à gauche de la zone de saisie sont rouges, ce qui indique que les propriétés
nameetskillsont invalides. Remarquez que les messages d'erreur sont masqués. C'est parce que le formulaire est intact : vous n'avez encore rien modifié.Saisissez un nom et cliquez à nouveau sur New Actor.
L'application affiche maintenant un message d'erreur
Name is required, car la zone de saisie n'est plus intacte. Le formulaire se souvient que vous avez saisi un nom avant de cliquer sur New Actor.Pour rétablir l'état intact des contrôles du formulaire, effacez tous les indicateurs de façon impérative en appelant la méthode
reset()du formulaire après avoir appelé la méthodenewActor().actor-form.component.html (réinitialiser le formulaire)
<button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()"> New Actor </button>Désormais, cliquer sur New Actor réinitialise à la fois le formulaire et les indicateurs de ses contrôles.
Soumettre le formulaire avec ngSubmit
L'utilisateur doit pouvoir soumettre ce formulaire après l'avoir rempli.
Le bouton Submit en bas du formulaire ne fait rien par lui-même, mais il déclenche un événement de soumission du formulaire du fait de son type (type="submit").
Pour répondre à cet événement, suivez les étapes ci-dessous.
-
Écouter ngOnSubmit
Liez la propriété d'événement
ngSubmitdu formulaire à la méthodeonSubmit()du composant actor-form.actor-form.component.html (ngSubmit)
<form (ngSubmit)="onSubmit()" #actorForm="ngForm"> -
Lier la propriété disabled
Utilisez la variable de référence de template
#actorFormpour accéder au formulaire qui contient le bouton Submit et créer un event binding.Vous allez lier la propriété du formulaire qui indique sa validité globale à la propriété
disableddu bouton Submit.actor-form.component.html (submit-button)
<button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid"> Submit </button> -
Lancer l'application
Remarquez que le bouton est activé, même s'il ne fait encore rien d'utile.
-
Supprimer la valeur de Name
Cela enfreint la règle « obligatoire » : le message d'erreur s'affiche, et remarquez que le bouton Submit est aussi désactivé.
Vous n'avez pas eu à relier explicitement l'état activé du bouton à la validité du formulaire. Le
FormsModulel'a fait automatiquement quand vous avez défini une variable de référence de template sur l'élément de formulaire enrichi, puis fait référence à cette variable dans le contrôle du bouton.
Répondre à la soumission du formulaire
Pour montrer une réponse à la soumission du formulaire, vous pouvez masquer la zone de saisie des données et afficher autre chose à sa place.
-
Envelopper le formulaire
Enveloppez tout le formulaire dans un
<div>et liez sa propriétéhiddenà la propriétéActorFormComponent.submitted.actor-form.component.html (extrait)
<div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <!-- ... all of the form ... --> </form> </div>Le formulaire principal est visible dès le départ, car la propriété
submittedvaut false jusqu'à ce que vous soumettiez le formulaire, comme le montre ce fragment deActorFormComponent:actor-form.component.ts (submitted)
submitted = false; onSubmit() { this.submitted = true; }Quand vous cliquez sur le bouton Submit, l'indicateur
submittedpasse à true et le formulaire disparaît. -
Ajouter l'état soumis
Pour afficher autre chose pendant que le formulaire est à l'état soumis, ajoutez le HTML suivant sous le nouveau
<div>d'enveloppe.actor-form.component.html (extrait)
<div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br /> <button type="button" class="btn btn-primary" (click)="submitted = false">Edit</button> </div>Ce
<div>, qui affiche un acteur en lecture seule avec des bindings d'interpolation, n'apparaît que lorsque le composant est à l'état soumis.L'affichage alternatif comprend un bouton Edit dont l'événement de clic est lié à une expression qui efface l'indicateur
submitted. -
Tester le bouton Edit
Cliquez sur le bouton Edit pour revenir à l'affichage du formulaire modifiable.
Résumé
Le formulaire Angular présenté sur cette page tire parti des fonctionnalités suivantes du framework pour prendre en charge la modification des données, la validation, et plus encore.
- Un template de formulaire HTML Angular
- Une classe de composant de formulaire avec un décorateur
@Component - La gestion de la soumission du formulaire par un binding sur la propriété d'événement
NgForm.ngSubmit - Des variables de référence de template comme
#actorFormet#name - La syntaxe
[(ngModel)]pour le two-way binding - L'utilisation d'attributs
namepour la validation et le suivi des changements des éléments de formulaire - La propriété
validde la variable de référence sur les contrôles de saisie, qui indique si un contrôle est valide ou doit afficher des messages d'erreur - Le contrôle de l'état activé du bouton Submit par un binding sur la validité de
NgForm - Des classes CSS personnalisées qui fournissent aux utilisateurs un retour visuel sur les contrôles invalides
Voici le code de la version finale de l'application :