Cette leçon du tutoriel montre comment ajouter à une application Angular un formulaire qui collecte des données utilisateur. Cette leçon part d'une application Angular fonctionnelle et montre comment y ajouter un formulaire.
Les données collectées par le formulaire sont envoyées uniquement au service de l'application, qui les écrit dans la console du navigateur. L'utilisation d'une API REST pour envoyer et recevoir les données du formulaire n'est pas traitée dans cette leçon.
Important : Nous vous recommandons d'utiliser votre environnement local pour cette étape du tutoriel.
Ce que vous allez apprendre
- Votre application dispose d'un formulaire dans lequel les utilisateurs peuvent saisir des données envoyées au service de votre application.
- Le service écrit les données du formulaire dans le journal de la console du navigateur.
-
Ajouter une méthode pour envoyer les données du formulaire
Cette étape ajoute au service de votre application une méthode qui reçoit les données du formulaire à envoyer vers leur destination. Dans cet exemple, la méthode écrit les données du formulaire dans le journal de la console du navigateur.
Dans le panneau Edit de votre IDE :
Dans
src/app/housing.service.ts, dans la classeHousingService, collez cette méthode à la fin de la définition de la classe.Méthode de soumission dans src/app/housing.service.ts
import {Service} from '@angular/core'; import {HousingLocationInfo} from './housinglocation'; @Service() export class HousingService { readonly baseUrl = 'https://angular.dev/assets/images/tutorials/common'; protected housingLocationList: HousingLocationInfo[] = [ { id: 0, name: 'Acme Fresh Start Housing', city: 'Chicago', state: 'IL', photo: `${this.baseUrl}/bernard-hermant-CLKGGwIBTaY-unsplash.jpg`, availableUnits: 4, wifi: true, laundry: true, }, { id: 1, name: 'A113 Transitional Housing', city: 'Santa Monica', state: 'CA', photo: `${this.baseUrl}/brandon-griggs-wR11KBaB86U-unsplash.jpg`, availableUnits: 0, wifi: false, laundry: true, }, { id: 2, name: 'Warm Beds Housing Support', city: 'Juneau', state: 'AK', photo: `${this.baseUrl}/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg`, availableUnits: 1, wifi: false, laundry: false, }, { id: 3, name: 'Homesteady Housing', city: 'Chicago', state: 'IL', photo: `${this.baseUrl}/ian-macdonald-W8z6aiwfi1E-unsplash.jpg`, availableUnits: 1, wifi: true, laundry: false, }, { id: 4, name: 'Happy Homes Group', city: 'Gary', state: 'IN', photo: `${this.baseUrl}/krzysztof-hepner-978RAXoXnH4-unsplash.jpg`, availableUnits: 1, wifi: true, laundry: false, }, { id: 5, name: 'Hopeful Apartment Group', city: 'Oakland', state: 'CA', photo: `${this.baseUrl}/r-architecture-JvQ0Q5IkeMM-unsplash.jpg`, availableUnits: 2, wifi: true, laundry: true, }, { id: 6, name: 'Seriously Safe Towns', city: 'Oakland', state: 'CA', photo: `${this.baseUrl}/phil-hearing-IYfp2Ixe9nM-unsplash.jpg`, availableUnits: 5, wifi: true, laundry: true, }, { id: 7, name: 'Hopeful Housing Solutions', city: 'Oakland', state: 'CA', photo: `${this.baseUrl}/r-architecture-GGupkreKwxA-unsplash.jpg`, availableUnits: 2, wifi: true, laundry: true, }, { id: 8, name: 'Seriously Safe Towns', city: 'Oakland', state: 'CA', photo: `${this.baseUrl}/saru-robert-9rP3mxf8qWI-unsplash.jpg`, availableUnits: 10, wifi: false, laundry: false, }, { id: 9, name: 'Capital Safe Towns', city: 'Portland', state: 'OR', photo: `${this.baseUrl}/webaliser-_TPTXZd9mOo-unsplash.jpg`, availableUnits: 6, wifi: true, laundry: true, }, ]; getAllHousingLocations(): HousingLocationInfo[] { return this.housingLocationList; } getHousingLocationById(id: number): HousingLocationInfo | undefined { return this.housingLocationList.find((housingLocation) => housingLocation.id === id); } submitApplication(firstName: string, lastName: string, email: string) { console.log( `Homes application received: firstName: ${firstName}, lastName: ${lastName}, email: ${email}.`, ); } }Vérifiez que l'application se compile sans erreur. Corrigez les éventuelles erreurs avant de passer à l'étape suivante.
-
Ajouter les fonctions du formulaire à la page de détails
Cette étape ajoute à la page de détails le code qui gère les interactions avec le formulaire.
Dans le panneau Edit de votre IDE, dans
src/app/details/details.ts:Après les instructions
importen haut du fichier, ajoutez le code suivant pour importer les classes de formulaire d'Angular.Imports de formulaires dans src/app/details/details.ts
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; @Component({ selector: 'app-details', imports: [ReactiveFormsModule], template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> <section class="listing-apply"> <h2 class="section-heading">Apply now to live here</h2> <form [formGroup]="applyForm" (submit)="submitApplication()"> <label for="first-name">First Name</label> <input id="first-name" type="text" formControlName="firstName" /> <label for="last-name">Last Name</label> <input id="last-name" type="text" formControlName="lastName" /> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit" class="primary">Apply now</button> </form> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; applyForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), email: new FormControl(''), }); constructor() { const housingLocationId = parseInt(this.route.snapshot.params['id'], 10); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } submitApplication() { this.housingService.submitApplication( this.applyForm.value.firstName ?? '', this.applyForm.value.lastName ?? '', this.applyForm.value.email ?? '', ); } }Dans les métadonnées du décorateur de
Details, modifiez la propriétéimportsavec le code suivant :Directive imports dans src/app/details/details.ts
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; @Component({ selector: 'app-details', imports: [ReactiveFormsModule], template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> <section class="listing-apply"> <h2 class="section-heading">Apply now to live here</h2> <form [formGroup]="applyForm" (submit)="submitApplication()"> <label for="first-name">First Name</label> <input id="first-name" type="text" formControlName="firstName" /> <label for="last-name">Last Name</label> <input id="last-name" type="text" formControlName="lastName" /> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit" class="primary">Apply now</button> </form> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; applyForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), email: new FormControl(''), }); constructor() { const housingLocationId = parseInt(this.route.snapshot.params['id'], 10); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } submitApplication() { this.housingService.submitApplication( this.applyForm.value.firstName ?? '', this.applyForm.value.lastName ?? '', this.applyForm.value.email ?? '', ); } }Dans la classe
Details, avant la méthodeconstructor(), ajoutez le code suivant pour créer l'objet du formulaire.Directive template dans src/app/details/details.ts
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; @Component({ selector: 'app-details', imports: [ReactiveFormsModule], template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> <section class="listing-apply"> <h2 class="section-heading">Apply now to live here</h2> <form [formGroup]="applyForm" (submit)="submitApplication()"> <label for="first-name">First Name</label> <input id="first-name" type="text" formControlName="firstName" /> <label for="last-name">Last Name</label> <input id="last-name" type="text" formControlName="lastName" /> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit" class="primary">Apply now</button> </form> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; applyForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), email: new FormControl(''), }); constructor() { const housingLocationId = parseInt(this.route.snapshot.params['id'], 10); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } submitApplication() { this.housingService.submitApplication( this.applyForm.value.firstName ?? '', this.applyForm.value.lastName ?? '', this.applyForm.value.email ?? '', ); } }Dans Angular,
FormGroupetFormControlsont des types qui vous permettent de construire des formulaires. Le typeFormControlpeut fournir une valeur par défaut et définir la forme des données du formulaire. Dans cet exemple,firstNameest unestringet sa valeur par défaut est une chaîne vide.Dans la classe
Details, après la méthodeconstructor(), ajoutez le code suivant pour gérer le clic sur Apply now.Directive template dans src/app/details/details.ts
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; @Component({ selector: 'app-details', imports: [ReactiveFormsModule], template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> <section class="listing-apply"> <h2 class="section-heading">Apply now to live here</h2> <form [formGroup]="applyForm" (submit)="submitApplication()"> <label for="first-name">First Name</label> <input id="first-name" type="text" formControlName="firstName" /> <label for="last-name">Last Name</label> <input id="last-name" type="text" formControlName="lastName" /> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit" class="primary">Apply now</button> </form> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; applyForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), email: new FormControl(''), }); constructor() { const housingLocationId = parseInt(this.route.snapshot.params['id'], 10); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } submitApplication() { this.housingService.submitApplication( this.applyForm.value.firstName ?? '', this.applyForm.value.lastName ?? '', this.applyForm.value.email ?? '', ); } }Ce bouton n'existe pas encore : vous l'ajouterez à l'étape suivante. Dans le code ci-dessus, les
FormControlpeuvent renvoyernull. Ce code utilise l'opérateur de nullish coalescing pour utiliser une chaîne vide par défaut si la valeur estnull.Vérifiez que l'application se compile sans erreur. Corrigez les éventuelles erreurs avant de passer à l'étape suivante.
-
Ajouter le balisage du formulaire à la page de détails
Cette étape ajoute à la page de détails le balisage qui affiche le formulaire.
Dans le panneau Edit de votre IDE, dans
src/app/details/details.ts:Dans les métadonnées du décorateur de
Details, modifiez le HTML dutemplatepour qu'il corresponde au code suivant afin d'ajouter le balisage du formulaire.Directive template dans src/app/details/details.ts
import {Component, inject} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocationInfo} from '../housinglocation'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; @Component({ selector: 'app-details', imports: [ReactiveFormsModule], template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> <section class="listing-apply"> <h2 class="section-heading">Apply now to live here</h2> <form [formGroup]="applyForm" (submit)="submitApplication()"> <label for="first-name">First Name</label> <input id="first-name" type="text" formControlName="firstName" /> <label for="last-name">Last Name</label> <input id="last-name" type="text" formControlName="lastName" /> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit" class="primary">Apply now</button> </form> </section> </article> `, styleUrls: ['./details.css'], }) export class Details { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocationInfo | undefined; applyForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), email: new FormControl(''), }); constructor() { const housingLocationId = parseInt(this.route.snapshot.params['id'], 10); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } submitApplication() { this.housingService.submitApplication( this.applyForm.value.firstName ?? '', this.applyForm.value.lastName ?? '', this.applyForm.value.email ?? '', ); } }Le template inclut maintenant un event handler
(submit)="submitApplication()". Angular utilise une syntaxe avec des parenthèses autour du nom de l'événement pour définir des événements dans le code du template. Le code à droite du signe égal est le code qui doit être exécuté lorsque cet événement est déclenché. Vous pouvez vous lier aux événements du navigateur et à des événements personnalisés.Vérifiez que l'application se compile sans erreur. Corrigez les éventuelles erreurs avant de passer à l'étape suivante.

-
Tester le nouveau formulaire de votre application
Cette étape teste le nouveau formulaire pour vérifier que, lorsque les données du formulaire sont soumises à l'application, elles apparaissent dans le journal de la console.
- Dans le panneau Terminal de votre IDE, exécutez
ng serves'il n'est pas déjà en cours d'exécution. - Dans votre navigateur, ouvrez votre application à l'adresse
http://localhost:4200. - Faites un clic droit sur l'application dans le navigateur et, dans le menu contextuel, choisissez Inspect.
- Dans la fenêtre des outils de développement, choisissez l'onglet Console. Assurez-vous que la fenêtre des outils de développement reste visible pour les étapes suivantes
- Dans votre application :
- Sélectionnez un logement et cliquez sur Learn more pour voir les détails du logement.
- Sur la page de détails du logement, faites défiler jusqu'en bas pour trouver le nouveau formulaire.
- Saisissez des données dans les champs du formulaire : n'importe quelles données conviennent.
- Choisissez Apply now pour soumettre les données.
- Dans la fenêtre des outils de développement, consultez la sortie du journal pour retrouver les données de votre formulaire.
- Dans le panneau Terminal de votre IDE, exécutez
Résumé : Dans cette leçon, vous avez modifié votre application pour ajouter un formulaire à l'aide de la fonctionnalité de formulaires d'Angular, et connecté les données saisies dans le formulaire à un composant à l'aide d'un event handler.
Pour plus d'informations sur les sujets abordés dans cette leçon, consultez :