Vous êtes sur la page 1sur 7

Angular 2

Formulaire :
Dans Angular il existe deux méthodes pour créer un formulaire.

1. Méthode Template

2. Méthode Réactive

Méthode Template :
Pour créer un formulaire dans Angular il faut importer le module FormsModule depuis la bibliothèque
@angular/forms.
Exemple :

<form>
<label for="emailInput">Inscrivez-vous pour recevoir notre newsletter !</label>
<input id="emailInput" name="userEmail" type="email" [(ngModel)]="userEmail">
<button type="submit">OK!</button>
</form>

La syntaxe [(ngModel)]="userEmail" permet de faire une liaison bidirectionnelle entre l’attribut userEmail de
notre composant et et notre document HTML.
Pour faire du attribute binding on utilise les crochets, il s’agit d’une liaison entre le composant et le template.
Pour faire du event binding on utilise les parenthèses, il s’agit d’une liaison entre le template et le composant.
Pour faire donc le Two-way-binding, la liaison bidirectionnelle, on utilise les deux, les crochets et les
parenthèses, d’où la syntaxe [(ngModel)].

ngSubmit :
Le directive ngSubmit permet de définir une méthode à appelé lorsque l’utilisateur clique sur un boutton submit.
Exemple :

<form (ngSubmit)="onSubmitForm()">

Ici, on par du principe que l’on possède une méthode onSubmitForm dans notre composant.

Référencement de formulaire :
Pour pouvoir envoyer tous les données du formulaire en même temps on utilise le référencement.
En important FormsModule dans le fichier de module chaque formulaire crée aura une référence ngForm. De
ce faite, etant donné que chaque formulaire aura un ngForm il faudrait definir notre propres nom de
référencement en utilisant le dièse (#).

<form #emailForm="ngForm" (ngSubmit)="onSubmitForm(emailForm)">

Angular 2 1
Ici notre objet de donnée s’appelle emailForm, il suffira maintenant de le passé en paramètre à notre méthode
de submit onSubmitForm.
Pour que le code fonctionne correctement il faut modifier la signature de notre méthode onSubmitForm pour qu’il
prenne l’objet emailForm en paramètre.

onSubmitForm(form: NgForm) {
console.log(form.value);
}

Ici, notre méthode onSubmitForm prend un objet NgForm en paramètre, qui lui sera fourni par notre template
(voir le code precedente).

Méthode réactive :
Là où les formulaires template sont définis par le contenu HTML du template, les formulaires réactifs sont
d'abord générés en TypeScript – on vient ensuite relier les différents input du template à l'objet du
formulaire.
Les formulaires réactifs offrent beaucoup plus de possibilités aux développeurs :

comme leur nom l'indique, les formulaires réactifs mettent à disposition des Observables pour réagir en
temps réel aux valeurs entrées par l'utilisateur ;

les formulaires réactifs permettent une validation beaucoup plus approfondie ;

pour générer des formulaires totalement dynamiques – c'est-à-dire des formulaires dont vous ne
connaissez pas la structure en amont – les formulaires réactifs sont la seule solution.

ReactiveFormsModule :
Comme pour les formulaires template, il faut ajouter un import à AppModule. Pour les formulaires réactifs, il faut
importer ReactiveFormsModule :

// ...
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule
],
//...

Pour créer un formulaire réactive nous avons besoin principalement de deux outils, dans notre composant TS,
qui sont FormGroup et FromBuilder.

FromGroup représente un objet formulaire avec un ensemble d’attribut qui vont représenté les inputs dans notre
template.
FormBuilder représente un service qui nous permet de créer un objet formulaire avec des attributs qu’on pourra
lier aux champs de notre formulaire de template. Exemple :

import { Component, OnInit } from '@angular/core';


import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
selector: 'app-new-face-snap',

Angular 2 2
templateUrl: './new-face-snap.component.html',
styleUrls: ['./new-face-snap.component.scss']
})
export class NewFaceSnapComponent implements OnInit {

snapForm!: FormGroup;

constructor(private formBuilder: FormBuilder) { }

ngOnInit(): void {
this.snapForm = this.formBuilder.group({
title: [null],
description: [null],
imageUrl: [null],
location: [null]
});
}

onSubmitForm() {
console.log(this.snapForm.value);
}

On utilise la méthode group du FormBuilder, en lui passant un objet :

les clés de l'objet correspondent aux noms des champs – ici, j'ai choisi les quatre champs du modèle
FaceSnap que l'utilisateur pourra entrer ;

les valeurs de l'objet correspondent à la configuration de chaque champ – pour l'instant, vous passez
uniquement null pour dire que la valeur par défaut de ces champs est null .

Comme avec les formulaires template, on accède au contenu du formulaire avec l'attribut value

Pour lier notre donnée de formulaire dans le TS depuis notre template on va utiliser la directive formGroup et
l’attribut formControlName.

💡 Le fait d'avoir importé ReactiveFormsModule vous permet de lier un objet de type FormGroup à un
<form> avec l'attribut formGroup .

Il faut attribuer un formControlName à chaque input que nous ajoutons à notre formulaire : ces noms doivent
correspondre aux noms des contrôles créés avec FormBuilder.

<form [formGroup]="snapForm">
<div class="form-group">
<label for="title">Titre</label>
<input id="title" type="text" formControlName="title">
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea id="description" type="text" formControlName="description" rows="4">
</textarea>
</div>
<div class="form-group">
<label for="imageUrl">URL de l'image</label>
<input id="imageUrl" type="text" formControlName="imageUrl">
</div>
<div class="form-group">
<label for="location">Lieu</label>
<input id="location" type="text" formControlName="location">
</div>
<div class="action-buttons">

Angular 2 3
<button type="submit" (click)="onSubmitForm()">Enregistrer</button>
</div>
</form>

Pour avoir un premier aperçu du côté "réactif" des formulaires réactifs, essayons d'afficher en temps réel un
objet nommée FaceSnap que l'utilisateur est en train de créer.
Dans le TypeScript, créons un Observable faceSnapPreview$ qui émettra des objets de type FaceSnap . Le signe
$ permet d’indiquer qu’il s’agit d’un observable.

//...
snapForm!: FormGroup;
faceSnapPreview$!: Observable<FaceSnap>;
//...

Branchons cet Observable aux changements de valeur du formulaire avec son attribut valueChanges , un
Observable qui émet la valeur du formulaire à chaque modification :

snapForm!: FormGroup;
faceSnapPreview$!: Observable<FaceSnap>;

ngOnInit(): void {
this.snapForm = this.formBuilder.group({
title: [null],
description: [null],
imageUrl: [null],
location: [null]
});

this.faceSnapPreview$ = this.snapForm.valueChanges;
}

Le seul souci ici est que le formulaire n'émet pas des objets de type FaceSnap : il manque des attributs. Il faut
donc utiliser l'un des opérateurs de Observable pour transformer les émissions en FaceSnaps valables –
l'opérateur map() :

snapForm!: FormGroup;
faceSnapPreview$!: Observable<FaceSnap>;

ngOnInit(): void {
this.snapForm = this.formBuilder.group({
title: [null],
description: [null],
imageUrl: [null],
location: [null]
});

this.faceSnapPreview$ = this.snapForm.valueChanges.pipe(
map(formValue => ({
...formValue,
createdDate: new Date(),
snaps: 0,
id: 0
}))
);
}

Les parenthèses qui contient notre objet permet d’indiquer que notre map va renvoyer un objet.

Angular 2 4
L’operateur trois point (…) avant la variable formValue permet d’indiquer que l’on souhaitre récuperer tous les
donnée de notre objet, en l’occurent le title, description, imageUrl et location.

Pour utiliser un observable il faut y souscrire et notre template HTML ne fait pas exception à la règle.
Pour souscrire à un observable depuis notre template on va utiliser le pipe async.

<div class="form-card">
<!-- ... -->
</div>
<div class="face-snap-card" *ngIf="faceSnapPreview$ | async as faceSnap">
<h2>{{ faceSnap.title | uppercase }}</h2>
<p>Mis en ligne {{ faceSnap.createdDate | date: 'à HH:mm, le d MMMM yyyy' }}</p>
<img [src]="faceSnap.imageUrl" [alt]="faceSnap.title">
<p>{{ faceSnap.description }}</p>
<p *ngIf="faceSnap.location">Photo prise à {{ faceSnap.location }}</p>
</div>

Ici on a un pattern très courant et extrêmement utile qui utilise la directive *ngIf , le pipe async , et le mot-
clé as . Cette approche :

souscrit à l'Observable ;

ajoute la <div> uniquement lorsque l'Observable émet ;

crée un alias pour l'émission qui est utilisable à l'intérieur de la <div> .

Cet alias permet de traiter les émissions de l'Observable comme si elles étaient des valeurs fixes. C'est ce qui
vous permet d'accéder facilement aux attributs du FaceSnap émis sans avoir à y souscrire de nouveau.

Validation :
Ajouter une validation aux formulaires réactifs est plutôt simple : il suffit de les ajouter à la configuration des
champs passés à la méthode group de FormBuilder.
Prenons un exemple avec le validateur required :

this.snapForm = this.formBuilder.group({
title: [null, [Validators.required]],
description: [null, [Validators.required]],
imageUrl: [null, [Validators.required]],
location: [null]
});

Un autre exemple avec le validateur pattern.

// ...
snapForm!: FormGroup;
faceSnapPreview$!: Observable<FaceSnap>;
urlRegex!: RegExp;
// ...

ngOnInit(): void {
this.urlRegex = /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/;

this.snapForm = this.formBuilder.group({
title: [null, [Validators.required]],
description: [null, [Validators.required]],
imageUrl: [null, [Validators.required, Validators.pattern(this.urlRegex)]],
location: [null]
});
}

Angular 2 5
💡 Validators s'importe depuis @angular/forms .

💡 Les Validators sont des fonctions, mais attention à ne pas mettre les parenthèses () . Par exemple,
ne mettez pas Validators.required() , mais bien Validators.required . On passe la fonction
comme argument – on ne l'appelle pas.

Pour empêcher l'utilisateur d'envoyer le formulaire s'il n'est pas valable, on peut lier l'attribut disabled du bouton
d'enregistrement à l'attribut invalid du FormGroup – si le formulaire n'est pas valable, le bouton
sera désactivé.

<!-- ... -->


<button type="submit" (click)="onSubmitForm()" [disabled]="snapForm.invalid">Enregistrer</button>
<!-- ... -->

💡 pattern est un Validator qui prend un argument, donc on doit lui ajouter les parenthèses,

contrairement à required .

Par défaut, les données sont emit en temps réel, mais on a la possibilité d’émettre uniquement lorsque
l'utilisateur change de champ, c'est-à-dire lors du blur des différents champs. Pour ceci, nous allons passer un
objet de configuration à la méthode group :

this.snapForm = this.formBuilder.group({
title: [null, [Validators.required]],
description: [null, [Validators.required]],
imageUrl: [null, [Validators.required, Validators.pattern(this.urlRegex)]],
location: [null]
}, {
updateOn: 'blur'
});

Module :
Un module permet de déclarer et de regrouper des components, services, directives, pipes, et même d'autres
modules.
Il existe trois types principaux de modules :

feature modules : ces modules encapsulent tous les éléments d'un "feature" de votre application – ce qui
définit un "feature" peut parfois être flou, mais dans l'exemple de l'application Snapface, on pourrait
distinguer deux features : la landing page, et toute la gestion des FaceSnaps ;

core modules : ce type de module contient tout ce que l'on importe une seule fois dans application (les
core modules sont eux-mêmes importés une seule fois, la majorité du temps dans AppModule) –
les services, les modèles, et les intercepteurs par exemple, ou des components comme
HeaderComponent dans Snapface ;

shared modules : ce sont des modules qui regroupent des éléments utilisés à plusieurs endroits de
l'application – il importe et déclare tous ces éléments et les réexporte, permettant à n'importe quel module

Angular 2 6
de tout importer d'un coup.

Lazy loading :
C’est une technique de routing qui dépend de l'architecture de modules et qui fera en sorte qu'Angular, au
moment du déploiement, crée des fichiers JS séparés pour chaque feature module. Ces fichiers sont ensuite
chargés au besoin – quand l'utilisateur accède à la route qui y correspond.
Pour qu'un module puisse être lazy loaded, il doit s'occuper de son propre routing.

Pour ce faire on créer un fichier du nom my-component-name-routing.module.ts, exemple: projet-


routing.module.ts.

import { NgModule } from '@angular/core';


import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [


{ path: ':id', component: SingleFaceSnapComponent },
{ path: '', component: FaceSnapListComponent },
{ path: 'create', component: NewFaceSnapComponent },
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})export class ProjetRoutingModule {}

Au lieu d'utiliser RouterModule.forRoot() (qui ne doit être appelée qu'une seule fois par votre routeur
racine), nous utilisons RouterModule.forChild() pour enregistrer ces routes au routeur déjà créé.
Pour implémenter le système de lazy loding dans notre application on peut utiliser un exemple de code
suivant :

const routes: Routes = [


{ path: 'facesnaps', loadChildren: () => import('./face-snaps/face-snaps.module').then(m => m.FaceSnapsModule) },
{ path: '', component: LandingPageComponent }
];

Ici, on se trouve dans le app-routing.module.ts.


La syntaxe loadChildren: () => import('./face-snaps/face-snaps.module').then(m => m.FaceSnapsModule) va
charger à la demande le module FaceSnapsModule qui se trouve dans le fichier face-snaps.module.

Angular 2 7

Vous aimerez peut-être aussi