Angular 8 : formulaire
Achref El Mouelhi
Docteur de l’université d’Aix-Marseille
Chercheur en programmation par contrainte (IA)
Ingénieur en génie logiciel
[email protected]
12-13 Avril 2018 1 / 32
Plan
1 Définition
2 Évènements
3 Liaison (binding) bidirectionnelle
4 Validation de formulaire
5 Soumission de formulaire
12-13 Avril 2018 2 / 32
Définition
Angular
Définition : Un formulaire
un outil graphique que nous créons avec le langage de description
HTML
il permet à l’utilisateur de saisir des données
et de les envoyer vers une autre page, vers une base de
données...
12-13 Avril 2018 3 / 32
Définition
Angular
Alors pourquoi Angular ?
Angular nous facilite
la récupération des données saisies
la validation et le contrôle des valeurs saisies
la gestion d’erreurs
...
12-13 Avril 2018 4 / 32
Évènements
Angular
Un évènement
action appliquée par l’utilisateur ou simulée par le développeur sur
un .component.html
un évènement déclenché ⇒ une méthode, dans le
.component.ts associé, exécutée
12-13 Avril 2018 5 / 32
Évènements
Angular
Un évènement
action appliquée par l’utilisateur ou simulée par le développeur sur
un .component.html
un évènement déclenché ⇒ une méthode, dans le
.component.ts associé, exécutée
Pour commencer
créer un composant formulaire
créer un chemin /formulaire permettant d’afficher ce
composant
12-13 Avril 2018 5 / 32
Évènements
Angular
Le fichier formulaire.component.ts Le fichier
formulaire.component.html
import { Component, OnInit } from ’@angular/
core’; <p>
formulaire works!
@Component({ </p>
selector: ’app-formulaire’,
templateUrl: ’./formulaire.component.html’
,
styleUrls: [’./formulaire.component.css’]
})
export class FormulaireComponent implements
OnInit {
constructor() { }
ngOnInit() {
}
}
12-13 Avril 2018 6 / 32
Évènements
Angular
Le fichier formulaire.component.ts Le fichier
formulaire.component.html
import { Component, OnInit } from ’@angular/
core’; <div>
<button (click)="
@Component({ direBonjour()">
selector: ’app-formulaire’, cliquer
templateUrl: ’./formulaire.component.html’ </button>
, </div>
styleUrls: [’./formulaire.component.css’]
})
export class FormulaireComponent implements
OnInit {
constructor() { }
ngOnInit() { }
direBonjour(){
console.log("Bonjour");
}
}
12-13 Avril 2018 7 / 32
Évènements
Angular
(eventBinding)
La valeur de l’attribut évènement situé entre () sera le nom d’une
méthode de FormulaireComponent
12-13 Avril 2018 8 / 32
Évènements
Angular
(eventBinding)
La valeur de l’attribut évènement situé entre () sera le nom d’une
méthode de FormulaireComponent
Explication
En cliquant sur le bouton cliquer, la méthode direBonjour()
est exécutée.
Bonjour est affiché dans la console
12-13 Avril 2018 8 / 32
Évènements
Angular
(eventBinding)
La valeur de l’attribut évènement situé entre () sera le nom d’une
méthode de FormulaireComponent
Explication
En cliquant sur le bouton cliquer, la méthode direBonjour()
est exécutée.
Bonjour est affiché dans la console
Et si on veut récupérer la valeur saisie dans une zone texte et l’afficher
dans une autre partie du composant.
12-13 Avril 2018 8 / 32
Évènements
Le fichier formulaire.component.ts Le fichier
formulaire.component.html
import { Component, OnInit } from ’@angular/
core’; <div>
<input type=text name=
@Component({ nom #nom>
selector: ’app-formulaire’, </div>
templateUrl: ’./formulaire.component.html’ <div>
, <button (click)="
styleUrls: [’./formulaire.component.css’] direBonjour(nom.
}) value)">
export class FormulaireComponent implements cliquer
OnInit { </button>
result = ""; </div>
constructor() { } <div>
Bonjour {{ result }}
ngOnInit() { } </div>
direBonjour(nom:string){
this.result = nom;
}
}
#nom est une variable locale contenant les attributs de cet élément HTML. Les variables locales
peuvent être utilisées avec tout élément HTML, <p>, <h>...
12-13 Avril 2018 9 / 32
Évènements
Angular
Remarque
Il est possible de simplifier le code précédant en utilisant le two
way binding
12-13 Avril 2018 10 / 32
Liaison (binding) bidirectionnelle
Angular
Plusieurs formes de binding
{{ interpolation }} : permet de récupérer la valeur d’un
attribut déclarée dans le .component.ts
[ one way binding ] : permet aussi de récupérer la valeur
d’un attribut déclarée dans le .component.ts
( event binding ) : permet au .component.ts de
récupérer des valeurs passées par le .component.html
12-13 Avril 2018 11 / 32
Liaison (binding) bidirectionnelle
Angular
Plusieurs formes de binding
{{ interpolation }} : permet de récupérer la valeur d’un
attribut déclarée dans le .component.ts
[ one way binding ] : permet aussi de récupérer la valeur
d’un attribut déclarée dans le .component.ts
( event binding ) : permet au .component.ts de
récupérer des valeurs passées par le .component.html
{{ interpolation }} est un raccourci de [ one way
binding ]
<p [textContent]= "result"></p>
<p> {{ result }} </p>
<!-- Les deux écritures sont équivalentes -->
12-13 Avril 2018 11 / 32
Liaison (binding) bidirectionnelle
Angular
Il est possible de combiner one way binding et event binding
Résultat : two way binding
Un changement de valeur dans .component.ts sera aperçu
dans .component.html et un changement dans
.component.html sera reçu dans .component.ts
12-13 Avril 2018 12 / 32
Liaison (binding) bidirectionnelle
Angular
Il est possible de combiner one way binding et event binding
Résultat : two way binding
Un changement de valeur dans .component.ts sera aperçu
dans .component.html et un changement dans
.component.html sera reçu dans .component.ts
two way binding
Pour la liaison bidirectionnelle, il nous faut la propriété ngModel
Pour pouvoir utiliser la propriété ngModel, il faut ajouter le
module FormsModule dans app.module.ts
12-13 Avril 2018 12 / 32
Liaison (binding) bidirectionnelle
Angular
Nouveau contenu d’app.module.ts
import { BrowserModule } from ’@angular/platform-browser’;
import { NgModule } from ’@angular/core’;
import { FormsModule } from ’@angular/forms’;
//+ les autres imports
@NgModule({
declarations: [
AppComponent,
AdresseComponent,
PersonneComponent,
FormulaireComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
12-13 Avril 2018 13 / 32
Liaison (binding) bidirectionnelle
Le fichier formulaire.component.ts Le fichier
formulaire.component.html
import { Component, OnInit } from ’@angular/
core’; <div>
<input type=text name=
@Component({ nom [(ngModel)]=nom>
selector: ’app-formulaire’, </div>
templateUrl: ’./formulaire.component.html’ <div>
, <button (click)="
styleUrls: [’./formulaire.component.css’] direBonjour()">
}) cliquer
export class FormulaireComponent implements </button>
OnInit { </div>
nom = ""; <div>
result = ""; Bonjour {{ result }}
constructor() { } </div>
ngOnInit() { }
direBonjour(){
this.result = this.nom;
}
}
Nous n’avons pas besoin de cliquer pour envoyer la valeur saisie dans le champ texte, elle est
mise à jour simultanément dans la classe quand elle est modifiée dans la vue.
12-13 Avril 2018 14 / 32
Liaison (binding) bidirectionnelle
Angular
Le fichier formulaire.component.ts Le fichier
formulaire.component.html
import { Component, OnInit } from ’@angular/
core’; <div>
<input type=text name=
@Component({ nom [(ngModel)]=nom>
selector: ’app-formulaire’, </div>
templateUrl: ’./formulaire.component.html’ <div>
, Bonjour {{ nom }}
styleUrls: [’./formulaire.component.css’] </div>
})
export class FormulaireComponent implements
OnInit {
nom = "";
constructor() { }
ngOnInit() { }
}
12-13 Avril 2018 15 / 32
Validation de formulaire
Angular
Considérant le formulaire formulaire.component.html
<form class=form-group>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom class
=form-control>
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=
prenom class=form-control>
</div>
<div>
<button type=submit class="btn btn-primary btn-
block">
Ajouter
</button>
</div>
</form>
12-13 Avril 2018 16 / 32
Validation de formulaire
Angular
Le fichier formulaire.component.ts
import { Component, OnInit } from ’@angular/core’;
@Component({
selector: ’app-formulaire’,
templateUrl: ’./formulaire.component.html’,
styleUrls: [’./formulaire.component.css’]
})
export class FormulaireComponent implements OnInit {
nom: string = "";
prenom: string = ""
constructor() { }
ngOnInit() { }
}
12-13 Avril 2018 17 / 32
Validation de formulaire
Angular
Pour soumettre le formulaire, il faut qu’il soit valide. Supposant que
les deux zones textes sont obligatoires
le bouton doit être initialement désactivé, on l’active que lorsque
le formulaire est valide
12-13 Avril 2018 18 / 32
Validation de formulaire
Angular
Commençons par rendre les deux zones textes obligatoires
<form>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom
required>
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=
prenom required>
</div>
<div>
<button type=submit>
Ajouter
</button>
</div>
</form>
12-13 Avril 2018 19 / 32
Validation de formulaire
Angular
Désactivons le bouton
<form>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom
required>
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=
prenom required>
</div>
<div>
<button type=submit disabled>
Ajouter
</button>
</div>
</form>
12-13 Avril 2018 20 / 32
Validation de formulaire
Angular
Question : comment réactiver le bouton ?
Écrire une fonction JavaScript pour tester si les deux champs ne
sont pas vides
Écrire une méthode dans la classe qui vérifiera à chaque saisie si
les deux champs ne sont pas vides pour réactiver le bouton
12-13 Avril 2018 21 / 32
Validation de formulaire
Angular
Question : comment réactiver le bouton ?
Écrire une fonction JavaScript pour tester si les deux champs ne
sont pas vides
Écrire une méthode dans la classe qui vérifiera à chaque saisie si
les deux champs ne sont pas vides pour réactiver le bouton
Avec les directives Angular, il y a plus simple
Utiliser la directive ngForm pour créer une variable locale
associée au formulaire
Exploiter la propriété valid de ngForm pour valider le formulaire
12-13 Avril 2018 21 / 32
Validation de formulaire
Angular
Pour le réactiver
<form #monForm=ngForm>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom
required>
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=
prenom required>
</div>
<div>
<button type=submit [disabled]=!monForm.valid>
Ajouter
</button>
</div>
</form>
12-13 Avril 2018 22 / 32
Validation de formulaire
Angular
Question : et si on veut afficher en rouge les champs obligatoires
non-renseignés ?
Utiliser les variables locales
Exploiter les propriétés CSS fournies par Angular
12-13 Avril 2018 23 / 32
Validation de formulaire
Angular
Utilisons les variables locales et affichons les classes CSS associées attribuées
par Angular
<form #monForm=ngForm>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom required #
lastName>
</div>
{{ lastName.className}}
<div>
Prenom : <input type=text name=prenom [(ngModel)]=prenom
required #firstName>
</div>
{{ firstName.className}}
<div>
<button [disabled]=!monForm.valid>
ajouter
</button>
</div>
</form>
12-13 Avril 2018 24 / 32
Validation de formulaire
Angular
Les classes CSS affichées pour les deux champs
form-control : classe Bootstrap qu’on a ajoutée
ng-untouched : classe Angular appliquée quand le champ n’est
pas touché (son inverse est ng-touched)
ng-pristine : classe Angular appliquée quand le champ est
vide (son inverse est ng-dirty)
ng-invalid : classe Angular appliquée quand le champ n’est
pas valid (son inverse est ng-valid)
12-13 Avril 2018 25 / 32
Validation de formulaire
Angular
Nettoyons le code précédent
<form #monForm=ngForm>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom required #
lastName>
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=prenom
required #firstName>
</div>
<div>
<button [disabled]=!monForm.valid>
ajouter
</button>
</div>
</form>
12-13 Avril 2018 26 / 32
Validation de formulaire
Angular
Définissons des propriétés pour quelques classes CSS fournies
par Angular
.ng-invalid:not(form){
border-left: 5px solid red;
}
.ng-valid:not(form){
border-left: 5px solid green;
}
12-13 Avril 2018 27 / 32
Validation de formulaire
Angular
On peut aussi afficher un message en cas de violation de contrainte
<form #monForm=ngForm>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom required #lastName
="ngModel">
</div>
<div [hidden]="lastName.valid">
Le nom est obligatoire
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=prenom required
#firstName="ngModel">
</div>
<div [hidden]="firstName.valid">
Le prenom est obligatoire
</div>
<div>
<button [disabled]=!monForm.valid>
ajouter
</button>
</div>
</form>
12-13 Avril 2018 28 / 32
Soumission de formulaire
Angular
Pour soumettre un formulaire, on peut utiliser la directive ngSubmit
<form #monForm=ngForm (ngSubmit)=ajouterPersonne()>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom required #lastName
="ngModel">
</div>
<div [hidden]="lastName.valid" class="alert alert-danger">
Le nom est obligatoire
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=prenom required #
firstName="ngModel">
</div>
<div [hidden]="firstName.valid">
Le prénom est obligatoire
</div>
<div>
<button [disabled]=!monForm.valid>
Ajouter
</button>
</div>
</form>
12-13 Avril 2018 29 / 32
Soumission de formulaire
Angular
Question : pourquoi utiliser (ngSubmit)
Faciliter le contrôle de la soumission du formulaire
12-13 Avril 2018 30 / 32
Soumission de formulaire
<div [hidden]="submitted">
<h1>Mon formulaire</h1>
<form #monForm=ngForm (ngSubmit)=ajouterPersonne()>
<div>
Nom : <input type=text name=nom [(ngModel)]=nom required #
lastName="ngModel">
</div>
<div [hidden]="lastName.valid" class="alert alert-danger">
Le nom est obligatoire
</div>
<div>
Prenom : <input type=text name=prenom [(ngModel)]=prenom required
#firstName="ngModel">
</div>
<div [hidden]="firstName.valid" >
Le prénom est obligatoire
</div>
<div>
<button [disabled]=!monForm.valid>
ajouter
</button>
</div>
</form>
</div>
<div [hidden]="!submitted">Personne ajoutée</div>
12-13 Avril 2018 31 / 32
Soumission de formulaire
Le fichier formulaire.component.ts
import { Component, OnInit } from ’@angular/core’;
import { Personne } from ’../classes/personne’;
@Component({
selector: ’app-formulaire’,
templateUrl: ’./formulaire.component.html’,
styleUrls: [’./formulaire.component.css’]
})
export class FormulaireComponent implements OnInit {
personnes: Array<Personne> = [];
nom: string = "";
prenom: string = "";
submitted: boolean = false;
constructor() { }
ngOnInit() { }
ajouterPersonne() {
this.personnes.push(new Personne(this.nom, this.prenom));
this.nom = "";
this.prenom = "";
this.submitted = true ;
}
}
12-13 Avril 2018 32 / 32