Angular.pdf

JaouadAssabbour 1,299 views 235 slides Nov 25, 2022
Slide 1
Slide 1 of 306
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67
Slide 68
68
Slide 69
69
Slide 70
70
Slide 71
71
Slide 72
72
Slide 73
73
Slide 74
74
Slide 75
75
Slide 76
76
Slide 77
77
Slide 78
78
Slide 79
79
Slide 80
80
Slide 81
81
Slide 82
82
Slide 83
83
Slide 84
84
Slide 85
85
Slide 86
86
Slide 87
87
Slide 88
88
Slide 89
89
Slide 90
90
Slide 91
91
Slide 92
92
Slide 93
93
Slide 94
94
Slide 95
95
Slide 96
96
Slide 97
97
Slide 98
98
Slide 99
99
Slide 100
100
Slide 101
101
Slide 102
102
Slide 103
103
Slide 104
104
Slide 105
105
Slide 106
106
Slide 107
107
Slide 108
108
Slide 109
109
Slide 110
110
Slide 111
111
Slide 112
112
Slide 113
113
Slide 114
114
Slide 115
115
Slide 116
116
Slide 117
117
Slide 118
118
Slide 119
119
Slide 120
120
Slide 121
121
Slide 122
122
Slide 123
123
Slide 124
124
Slide 125
125
Slide 126
126
Slide 127
127
Slide 128
128
Slide 129
129
Slide 130
130
Slide 131
131
Slide 132
132
Slide 133
133
Slide 134
134
Slide 135
135
Slide 136
136
Slide 137
137
Slide 138
138
Slide 139
139
Slide 140
140
Slide 141
141
Slide 142
142
Slide 143
143
Slide 144
144
Slide 145
145
Slide 146
146
Slide 147
147
Slide 148
148
Slide 149
149
Slide 150
150
Slide 151
151
Slide 152
152
Slide 153
153
Slide 154
154
Slide 155
155
Slide 156
156
Slide 157
157
Slide 158
158
Slide 159
159
Slide 160
160
Slide 161
161
Slide 162
162
Slide 163
163
Slide 164
164
Slide 165
165
Slide 166
166
Slide 167
167
Slide 168
168
Slide 169
169
Slide 170
170
Slide 171
171
Slide 172
172
Slide 173
173
Slide 174
174
Slide 175
175
Slide 176
176
Slide 177
177
Slide 178
178
Slide 179
179
Slide 180
180
Slide 181
181
Slide 182
182
Slide 183
183
Slide 184
184
Slide 185
185
Slide 186
186
Slide 187
187
Slide 188
188
Slide 189
189
Slide 190
190
Slide 191
191
Slide 192
192
Slide 193
193
Slide 194
194
Slide 195
195
Slide 196
196
Slide 197
197
Slide 198
198
Slide 199
199
Slide 200
200
Slide 201
201
Slide 202
202
Slide 203
203
Slide 204
204
Slide 205
205
Slide 206
206
Slide 207
207
Slide 208
208
Slide 209
209
Slide 210
210
Slide 211
211
Slide 212
212
Slide 213
213
Slide 214
214
Slide 215
215
Slide 216
216
Slide 217
217
Slide 218
218
Slide 219
219
Slide 220
220
Slide 221
221
Slide 222
222
Slide 223
223
Slide 224
224
Slide 225
225
Slide 226
226
Slide 227
227
Slide 228
228
Slide 229
229
Slide 230
230
Slide 231
231
Slide 232
232
Slide 233
233
Slide 234
234
Slide 235
235
Slide 236
236
Slide 237
237
Slide 238
238
Slide 239
239
Slide 240
240
Slide 241
241
Slide 242
242
Slide 243
243
Slide 244
244
Slide 245
245
Slide 246
246
Slide 247
247
Slide 248
248
Slide 249
249
Slide 250
250
Slide 251
251
Slide 252
252
Slide 253
253
Slide 254
254
Slide 255
255
Slide 256
256
Slide 257
257
Slide 258
258
Slide 259
259
Slide 260
260
Slide 261
261
Slide 262
262
Slide 263
263
Slide 264
264
Slide 265
265
Slide 266
266
Slide 267
267
Slide 268
268
Slide 269
269
Slide 270
270
Slide 271
271
Slide 272
272
Slide 273
273
Slide 274
274
Slide 275
275
Slide 276
276
Slide 277
277
Slide 278
278
Slide 279
279
Slide 280
280
Slide 281
281
Slide 282
282
Slide 283
283
Slide 284
284
Slide 285
285
Slide 286
286
Slide 287
287
Slide 288
288
Slide 289
289
Slide 290
290
Slide 291
291
Slide 292
292
Slide 293
293
Slide 294
294
Slide 295
295
Slide 296
296
Slide 297
297
Slide 298
298
Slide 299
299
Slide 300
300
Slide 301
301
Slide 302
302
Slide 303
303
Slide 304
304
Slide 305
305
Slide 306
306

About This Presentation

ce cours vous permettra, de découvrir les fondamentaux du framework angular, ainsi apprendre le framwork par pratique, avec des exemple sur chaque model


Slide Content

Angular
Introduction au développement d'applications Web
Créer rapidement des applications performantes
Jaouad assabbour

Objectifs
Jaouad Assabbour
2
•Comprendre les notions de base d’une SPA
•Savoir créer des composants Angular Complets
•Comprendre les services
•Connaitre les cycles de vie
•Savoir gérer des routes
•Savoir gérer les formulaires
•Savoir tester son application
•Mettre en place un projet

Plan
Jaouad Assabbour 3
1.Introduction
1.Les composants
2.Le data binding
3.Les directives
4.Les services et l’injection de dépendance
2.Concepts avancés
1.Le routing
2.Les formulaires
3.Les modules
3.Les tests

4Jaouad assabbour
Prérequis
Prérequis pour suivre cette formation

5Jaouad Assabbour
Prérequis
Bonnes connaissances de :
•TypeScript (ou Javascript ES6)
•HTML
•CSS
Idéalement :
•Bootstap
•Terminal (bash ou cmd.exe)

Prérequis-Installations
6Jaouad Assabbour
Node.js
https://nodejs.org/en/download/
node-v
Angular-CLI
npminstall -g @angular/cli
ng-v
Visual Studio Code (optionnel)
https://code.visualstudio.com/download

7Jaouad Assabbour
Introduction
Qu'est-ce qu'Angular?

8Jaouad Assabbour
Qu'est-ce qu'Angular ?
•Framework complet open source
•Présenté par Google en 2009
•Régulièrement mis à jour
•Basé sur les composants web
•Développement
•d’applications clientes web mono-page
(Single Page Application)
•concernant de nombreuses fonctionnalités

QQ
9Jaouad Assabbour
Qui utilise Angular
https://www.madewithangular.com/

10
Librairie ou Framework
Jaouad assabbour
•Angular est un framework .
•La différence des librairies, un framework impose davantage de
formalisme .C a n’est n i une bonne ni une mauvaise chose.
•Différence entre librairie et framework?
•Libraire:Votre code
appelle la librairie
•Framework: Le
framework appellele
développeur

Single Page Application?
Jaouad Assabbour 11
Application Client (Qui tourne coté client)
Distinct des Application Serveur / Mutli Page
Applications
Application Serveur, le serveur gère en interne :
-Logique
-Routing
-Vue
Application Client : Le serveur retourne l’application
(Logique, Routing, Vue) au client

Multi Page Application
12Jaouad Assabbour

Single Page Application
13Jaouad Assabbour

14Jaouad Assabbour
Petit historique
A l’origine utilisé pour Gmail, puis très vite étendu à de
nombreux projets internes de Google
• Initialement développé entièrement en JS (AngularJS)
• L’environnement et les standards de JS évoluant,l’équipe
de développement ne peut malheureusement pas impacter
ces améliorations du langage au framework et bloque
Angular en v1.

18Jaouad Assabbour
Avertissement
• La v2 d’AngularJS est annoncée pour 2014 mais sort
finalement en 2016 avec 2 ans de retard
• Lorsque la v2 sort, elle ne possède pas de
compatibilité des cendante (impossible de migrer
sans réécrire tout le code)
• Ces deux problèmes majeurs ont permis l’essort de
la concurrence : ReactJS (Facebook)
• De fait, beaucoup de projets AngularJS n’ont jamais
migré et AngularJS est toujours maintenu

19Jaouad assabbour
Les versions d’Angular
•Angular 1 (ou AngularJS) lancé 2010: utilisant le JavaScript
•Angular 2 lancé en 2016 : remplacement du JavaScript par
TypeScript, réécriture complète du core
•Angular 4 :mars 2017
•Angular 5 : novembre 2017
•Angular 6 : mai 2018
•Angular 7 :octobre 2018
•Angular 8 : mai 2019
•Angular 9 : février 2020
•Angular 10 : juin2020

20Jaouad Assabbour
Principes de base
Ce framework s’appuie sur plusieurs principes
présentés en détails dans les sections suivantes.
• Organisation par composants
• TypeScript
• Les spécifications ES6
• DOM Virtuel

21Jaouad Assabbour
Orienté composants
• L’organisation d’une application Angular se fait par
composants. Un composant correspond à un élément réutilisable,
indépendant et responsable d’une seule action métier.
• De cette manière, une application sera faite de l’assemblage d’un
ensemble de composants.
Meilleure organisation
Meilleure réutilisabilité
Meilleure testabilité
Meilleure maintenabilité

Typescript
22Jaouad Assabbour
Langage de programmation scripté orienté objet à
classes, open source influencé par C# et
JavaScript
développé et présenté par MicroSoft en 2012 :
• typer les variables
• définir des classes et des interfaces
• utiliser les annotations (les décorateurs)
• exporter et importer des module

24Jaouad Assabbour
Web
Components
Ce qui se cache derrière les composants Angular

Jaouad Assabbour 25
Components
Les composants sont une combinaison de plusieurs
technologies, permettant de réaliser des interfaces
graphiques réutilisables :
•Concrètement, un component est une brique autonome,
réutilisable, responsable d'une action métier et qui gère
ses propres données (state

Jaouad assabbour 37
Installation
Installation et création de notre première application

38Jaouad assabbour
Créer un premier projet
>Woud you like to add Anguar routing ? (Y/N)
>Which style sheet format would you like to use ?
Angular CLI est un outil en ligne de commande pour démarrer
rapidement un projet, déjà configuré avec Webpack comme un outil de
construction, des tests, du packaging, etc…
ng new [app-name] <options>

Cd [app-name]
ng serve–o
Cette opération prend un peu de temps car elle installe également l’arbre de dépendances
Une fois l’opération terminée, on peut lancer l’application par cette ligne de commande :
Cela démarre un serveur HTTP local, avec
rechargement à chaud. Ainsi, à chaque modification de
fichier, l’application sera rafraîchie dans le navigateur
Jaouad Assabbour

En plus de la commande new qui permet de créer un projet, Angular CLI nous aidera
tout au long des développements avec bien d’autres commandes utiles que nous
verrons :
Jaouad Assabbour 43
Commad Description
build Compile les sources dans un repertoire dist
e2e Lance les tests bout en bout avec Protractor.
generate Génère ou modifie des fichiers
lint Lance les outils de linting
test Lancer les tests untiaires

• Installer bootstrap dans l’applicatio npm install bootstrap@latest –save
• Raccorder bootstrap à notre application Dans le fichier angular.json, trouver
l’array des styles et y rajouter le path vers le fichier css de bootstrap
node_modules/bootstrap/dist/css/bootstrap.min.css
• Vider complètement le fichier app.component.html et relancer la commande
serve
Jaouad Assabbour 43

Jaouad Assabbour 43

Arborescence d'Angular
Arborescence d'une application Angular
jaouad assabbour 44

4
5
Jaouad assabbour
L'arborescence d ' Angular
À la racine du projet, on retrouve
l’ensemble d e s f i c h i e r s de c o n f i g u r a t i on:
•e2e : contenant les f ichiers de tests
end-to-end
•node_modules : les dépendances
•src : le dossier où setrouvent tous les
fichiers sources du projet

4
6
Jaouad Assabbour
L'arborescence d ' A n g u l a r
•.editorconfig :Fichier
de configuration des
éditeurs pour garder une
cohérence dans le code
quelque soit l’IDE.
•.gitignore: les fichiers non
trackés par git

4
7
Jaouad Assabbour
L'arborescence d'Angular
•angular.json: le fichier de
configuration princial du projet.
•C’est lui qui décritl’architecture de
l’application, les sources, lesfichiers
de configuration, les scripts ...
•Cette configuration est lue par le cli,
notamment lorsque des commandes
comme build, serve, ou test sont
lancées.

4
8
Jaouad assabbour
L'arborescence d'Angular
•karma.conf.js: le fichier
de configuration Karma qui
est un outil permettant de
lancer des tests sur une
série de navigateurs
automatiquement. Il est
déjà configuré pour être
exécuté sur le navigateur
Chrome avec la librairie de
test Jasmine

4
9
Jaouad assabbour
L'arborescence d'Angular
•package.json et
package.lock.json : le
fichier de déclaration des
dépendances et de sous
dépendances NPM
installées lors de la création
du projetet qui va évoluer à
chaque fois qu’on va ajouter
des dépendances

5
0
Jaouad assabbour
L'arborescence d'Angular
•README.md : le fichier de
présentation du projet au format
Markdown
•tsconfig.json,
tsconfig,app.json,
tsconfig.spec.json:
•La configuration typescript
respectivement:
•Pour tous les projets
•Pour l’application
•Pour les fichiers de test
•tslint.json: le fichier définissant les
règles de codage TypeScript.

5
1
Jaouad assabbour
L'arborescence d'Angular
•src/app: le dossier des sources et la logique
métiers du projet.
•src/assets: le dossier pour les ressources
additionnelles (images, polices, sons,
vidéos...)
•src/environments: fichiers de configuration
spécifiques aux environnements d’exécution.
Les fichiers contenus dans ce dossier
permettent de définir la configuration
spécifique à chaque environnement (prod ou
dev, dev étant la valeur par défaut)

5
2
Jaouad assabbour
L'arborescence d'Angular
•src/index.html : Le fichier html
principal qui sera servi lorsque l’on
arrive sur le site. Le CLI ajoute
automatiquement tous les fichiers JS
et CSS (donc pas besoin de les y
ajouter avec des <link> ou des
<script>)
•src/main.ts : le point d’entrée
principal de l’application. C’est lui qui lance
le module racine

5
3
Jaouad assabbour
L'arborescence d'Angular
•src/polyfill.ts : polyfill
pour la compatibilité
navigateurs
•src/styles.css: Le fichier css
principal qui doit s’appliquer à toute
l’application
• src/test.ts : le point d’entrée
principal pour les tests unitaires de
l’application (à priori, pas besoin d’y
toucher).

5
4
Jaouad assabbour
L'arborescence d'Angular
•app-routing.module.ts : le module
de routage principal
•app.component.css : le fichier contenant le
code CSS associé au composant web
•app.component.html : le fichier contenant
le code HTML associée au composant web
•app.component.spec.ts : le fichier de test
du composant web
•app.component.ts : la classe
associée au composant web
•app.module.ts: la classe correspondante au
module principal

La philosophie
d'Angular
Comment sont structurées les applications Angular ?
Jaouad Assabbour 55

La philosophie d ' Angular
Angular est unframework orienté composant
On écrit de petits composants, et assemblés,
ils vont constituer une application complète
Les composants sont organisés de façon hiérarchique, comme le DOM :
un composant racine aura des composants enfants, qui auront chacun des
enfants, etc.
Jaouad assabbour

57Jaouad assabbour
La philosophie d'Angular
Par exemple je vais pouvoir définir un composant catégorie qui
contiendra :
•Un composant liste produits, qui lui-même contiendra:
•plusieurs composants itemproduit
•un composant pagination
•Uncomposantfiltre qui lui-mêmecontiendra
•un composant filtre deprix
•un composant filtre detaille
•un composant filtre decouleur

Un composant est juste un bloc de construction réutilisable, basée
sur les web components que nous avons vu plus tôt. L’application
est elle même un composant comme les autres. Nous allons bientôt
voir comment construire un petit composant, et la syntaxe des
templates. Il y a un autre concept au coeur d’Angular : l’injection de
dépendance (Dependency Injection ou DI). Nous le verrons plus
tard également

Composants: Blocs de
construction réutilisables.
Contrôlent la vue (html) et peuvent
communiquer avec d'autres
composants ou services.
Modules : un ensemble de plusieurs composants et
services qui décrivent une partie spécifique de notre
application. Ils ne contrôlent pas le html mais permettent
la communication entre les parties de notre application
(Module de paiement, module administration, module
compte utilisateur ... etc)
Jaouad assabbour

Services: Le service est une
classe contenant des
fonctionnalités dont les
composant sont besoin avec un
but spécifique.
On peut ainsi séparer :
•les fonctionnalités liées à la vue dans les
composants
•les autres types de traitement (communication
serveur, validation d'input...) dans les services.
Jaouad assabbour

61Jaouad assabbour
Composant
Les composants, briques de base d'une application angular

62Jaouad assabbour
Composant
Au démarrage, notre application comporter un premier composant :
AppComponent
Le code du composant se trouve dans le fichier
app.component.ts
Le composant est une classe
TypeScript qui est décorée
avec le décorateur
@Component (nous
reviendrons sur les
décorateurs plus tard)
@Component({
selector:'app-root',
templateUrl:'./
app.component.html',styleUrls:['./
app.component.scss'],
})
exportclassAppComponent{
constructor(){}
}

Dans le décorateur, nous pouvons spécifier le sélecteur, c’est-à-dire la
balise qui va correspondre au composant. Cela veut dire qu’en écrivant
<app-root></app-root>
dans du HTML, c’est le composant AppComponent qui va être chargé. A
chaque fois que le sélecteur est rencontré, Angular va créer une nouvelle
instance du composant.
@Component({
selector:'app-root',
templateUrl:'./
app.component.html',styleUrls:['./
app.component.scss'],
})
Jaouad assabbour

64Jaouad assabbour
Contenu de index.html
<!doctypehtml>
<htmllang="en">
<head>
<metac ha r s et="utf-8">
<title>Todo</title>
<basehref="/">
<metaname="viewport"content="width=device-width,initial-scale=1">
<linkrel="icon"type="image/x-icon"href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>
<app-root></app-root> est le composant racine de notre
application. Il est appelé dans le fichier index.html

Jaouad Assabbour 65
Contenu de app.component.ts
•@Component : décorateur Typescript. C'est ce
qui déclare cette classe comme
un composant
•selector: la balise selector
correspodnante
•templateUrl : le html du composant
@Component({
selector:'app-root',
templateUrl:'./
app.component.html',styleUrls:
['./app.component.scss'],
})
exportclassAppComponent
{constructor(){}
•StyleUrls: l e s C S S d e
}
composant
•AppComponent:n o m de la classe du
composant

66Jaouad Assabbour
Compsant
Un composant a besoin
d'une vue. Pour définir une
vue, on peut définir un
template dans un fichier
séparé, avec l'attribut
templateURL
Ou via un template inline
(directement dans le code
du composant) via l'attribut
template (pour les petits
composants simples)
Ici on intègre un composant
first dans le composant
racine app.component.ts
@Component({
selector:'app-root',
template:'<app-first></appfirst>',styles:
['div{border:1pxblacksolid}'],
})
@Component({
selector:'app-root',
templateUrl:'./app.component.html',
styleUrls:['./app.component.scss'],
})

@Component({
selector:'app-root',
template:'<app-first></appfirst>',styles:
['div{border:1pxblacksolid}'],
})
Les styles qu’on définit dans un composant (soit dans
l’attribut styles, soit dans un fichier CSS dédié avec
styleUrls) sont limités à ce composant et seulement celui-ci
Cela s’appelle l’encapsulation de style
Jaouad assabbour

68Jaouad Assabbour
Générer un composant
On peut aussi créer un squelette de composant :
ng generate component [component-name]
(ou ng g c [component-name])
Cela va créer :
le fichier de composant ( .ts )
le template associé ( .html )
la feuille de style ( .css )
le fichier de test ( .spec.ts )
Bonne pratique : créer un répertoire spécifique aux
composants (ex : ng g c components/[component-name])

Outre les composants, la commande ng generate
permet de créer d’autres types de fichiers, parmi les quels :
• ng g class
• ng g directive
• ng g enum
• ng g guard
• ng g interface
• ng g module
• ng g pipe
• ng g service

71Jaouad assabbour
Interpolation
Comment afficher des variables dans le template

72Jaouad Assabbour
Interpolation
exportclassFirstComponentimplementsOnI
nit{
title='MyFirstComponent';
nbUser=145;constructor()
{}ngOnInit():void{}
}
<h1>{{title}}</h1>
<p>therearecurrently{{nbUsers}}online</
p>
component.ts afficher des
variables dans notre template.
C'est possible avec
l’interpolation.
L'interpolation permet
d'afficher dans le html des
properties définies dans la classe du
composant
{{nomVariable}}
first.component.ts
first.component.html

Ici notre template a été enrichi avec une balise <h1>, utilisant
la fameuse notation avec double-accolades (les
"moustaches") pour indiquer que cette expression doit être
évaluée. Ce type de templating est de l’interpolation
On devrait maintenant voir
dans le navigateur :
N'importe quelle expression typescript valide
peut être évaluée de la sorte :
{{2 + 2}}
{{ tab[0] }}
{{user.name}}
{{getUsers()}}
Jaouad assabbour

En utilisant l'interpolation, une relation de type one-
way binding est alors créée. Cette relation implique
que si le composant modifie les données, la vue sera
automatiquement mise à jour en temps réel.
Par contre l’inverse n’est pas vrai, si la vue est mise à
jour (via un formulaire par exemple), les données du
composant ne le seront pas pour autant.
Si on essaye d’afficher une variable qui n’existe pas,
au lieu d’afficher undefined, Angular affichera une
chaîne vide. Et de même pour une variable null
Jaouad assabbour

75Jaouad Assabbour
Safe navigation operator
Maintenant,au lieu d’une valeur
simple, disons que notre
composant a un objet user plus
complexe, décrivant l’utilisateur
courant.
En cas d'erreur dans le nom des
variable interpolées, on déclenche
une erreur dans la console.
Pour éviter cette erreur nous
allons plutôt écrire de cette
façon avec le ? appelé Safe
Navigation Operator (opérateur
de navigation sûre)
user={name:"David"}
<p>Welcome{{users.name}}</p>
<p>Welcome{{users?.name}}</p>

77Jaouad Assabbour
Binding
depropriétés

78Jaouad Assabbour
Property Binding
Une autre forme de one-way binding est le property binding.
Dans Angular, on peut écrire dans toutes les propriétés du
DOM avec des attributs spéciaux sur les éléments HTML,
entourés de crochets []
<p[property]="value"></p>
Property : le nom de la propriété du DOM à
modifier
value : seraici remplacée par sa valeur dans la
classe correspondante. La chaine entre caractère
sera interprétée.

79Jaouad Assabbour
textContent
La propriété [textContent] permet demodifier le texte à
l'intérieur d'un élément. Defait, l'interpolation que nous
utilisions plus haut pour afficher le nom de l’utilisateur:
<p> {{user.name}} </p>
Est en fait un raccourci pour la notation suivante :
<p[textContent]="user.name"></p>
Les deux notations se valent complètement si la valeur
interpolée est une chaine de caractères.

80
selected
Jaouad Assabbour
Les propriétés peuvent aussi avoir des valeurs
booléennes. Par exemple, il existe l’attribut
[selected] sur la balise <option> :
<option [selected]="isSelected" value="fr">Français</option>
L’option sera sélectionnée si isSelected vaut
true, et ne sera pas sélectionné si elle vaut false
A chaque fois que la valeur de isSelected
changera, la propriété selected sera mise à jour

hidden
81Jaouad Assabbour
Si on veut cacher un élément, on peut
utiliser la
propriété standard [hidden] :
<div [hidden]="isHidden">Hidden or not</div>
Et la <div> ne sera cachée que si isHidden
vaut true, car Angular travaillera
directement avec la propriété hidden du
DOM

style
Jaouad Assabbour 82
On peut aussi accéder à des propriétés html et css comme
l’attribut color de la propriété style :
<p [style.color]="foreground">Texte avec une couleur</p>
Si la valeur de l’attribut foreground est modifiée à
green, le texte deviendra vert

class
83Jaouad Assabbour
Il est également possible de rajouter des classes css à nos éléments:
<p [class]="paragraph">Texte avec une classe</p>
<p [class.paragraph]="true">Texte avec une classe</p>

84
Property Binding
Jaouad Assabbour
N'importe quel attribut html peut être assigné de cette façon :
<img[src]="imgSource"> modifier la propriété src de l'image
<a[href]="link"> modifier la propriété href du lien
<p[textContent]='toto'> modifier le contenu texte de l'élément
<input[value]="firstName"> modifier la valeur de l'input
<input[title]="firstName"> modifier la propriété title
<input[hidden]="isHidden"> modifier la propriété hidden
<input[disabled]="isDisabled"> modifier la propriété disabled
<option[selected]="isSelected"> modifier la propriété selected (sélection par
défaut)
<p[class]="container"> attribuer la classe container à l'élément
<p[class.container]="true"> attribuer une classe de manière
conditionnelle
<p[style]="color:red"> attribuer un style à l'élément
<p[style.color]="red"> attribuer une propriété de style
conditionnellement
<p[attr.nomAttribut]="value"> modifier une proprié

87Jaouad assabbour
Evénements

88Jaouad Assabbour
Evénements
Le navigateur déclenche des événements tels que : click, keyup,
mousemove, etc…
Il est possible de binder des fonctions à nos événements en entourant
l’événement du DOM avec des parenthèses()
Un clic sur le bouton de l’exemple ci-dessus déclenchera un appel
à la méthode onSave()

89Jaouad Assabbour
Evénements : bubbling
Angular écoute les événements de l’élément et ceux de ses enfants, il
va donc aussi réagir sur les événements (bubbling up)
Même si l’utilisateur clique sur le button dans la div, la méthode
onButtonClick() sera appelée, car l’événement se propage vers le
haut.

Il est possible de transmettre depuis le template l’objet event
à la méthode appelée pour la récupérer dans le TS.
Pour cela, on passes implement $eventà la méthode:
Ensuite on peut gérer cet événement dans la classe du
composant :
Jaouad Assabbour

91Jaouad assabbour
Evénements
Pour empêcher le bouilonnement, on peut ensuite utiliser
event.stopPropagation()
Pour empêcher le comportement par défaut, on peut
utiliser event.preventDefault()
Le cas typique étant pour empêcher l’event submit
d’un formulaire de recharger notre page

92Jaouad Assabbour
Evénements : clavier
Une autre fonctionnalité est la gestion des
événements du clavier :
Chaque fois qu’on appuie sur la touche space, la
méthode onSpacePress() sera appelée
(keydown.nomTouche)
On peut faire des combos, comme (keydown.alt.a),
etc...

94Jaouad Assabbour
TwoWayB i n d i n g

95Jaouad Assabbour
TwoWayBinding
Nous avons vu plusieurs formes de binding :
• {{ interpolation }} : qui permet de passer au
template la valeur des attributs du composant
• [ property-binding ] : idem (l'interpolation est
d'ailleurs une syntaxe raccourcie de one way
binding)
• ( event-binding ) : qui permet de récupérer des
valeurs ppassées dans le template vers le composant

Il est possible de combiner l'event binding et le one way
binding. Résultat : le two way binding.
Un changement de valeur dans le composant sera reçu
dans le template, et inversement.
Pour pouvoir utiliser le two way binding, il faut
charger le module de formulaires dans
app.module.ts
import{FormsModule}from'@angular/forms';
imports:[BrowserModule,FormsModule]
Jaouad assabbour

<input[(ngModel)]="user.name">
<p>Hello{{user.name}}!</p>
Nottons l'utilisation combinée de one way binding etevent
binding : [(ngModel)]='value'
Si je définis une propriété user dans mon component, je peux
alors la binder à mon template comme ceci :
ngModel est une directive permettant d’établir une relation de type
two-way entre une propriété du modèle et la vue (input, textarea).
Nous aurons l’occasion d’en voir d’autres
Jaouad assabbour

Onewaybinding : on
affiche dans l'input la
valeur provenant de la
classe.
Eventbinding : si la valeur de
l'input change, elle est envoyée
à la classe
Si on affiche la valeur via
l'interpolation, on peut constater
qu'elle change avec l'input.
Jaouad assabbour
<input[(ngModel)]="user.name">
<p>Hello{{user.name}}!</p>

A noter, la syntaxe
[(ngModel)]='value'
est une syntaxe simplifiée de
[ngModel]='value'(ngModelChange)='value=$event'
Ceci est utile lorsqu'on utilise le Safe Navigation Operator,
incompatible avec le two way binding (cet opérateur ne peut
pas être utilisé dans un assignement)
On utilisera donc cette syntaxe. Exemple :
<input[ngModel]="user?.email"(ngModelChange)="user.email=$event"
Jaouad assabbour

102Jaouad assabbour
Interractionentre
composants

103Jaouad Assabbour
Interractionentre composants
Une application Angular est composée de plusieurs composants qui s'imbriquent
entre eux. On peut donc ajouter le sélecteur d’un premier composant dans le
template d’un deuxième composant
• on appelle le premier composant : composant enfant
• on appelle le deuxième composant : composant parent
En utilisant les décorateurs @Input() et @Output() les deux composants
peuvent échanger de données
@Input() : permet a un composant fils de récupérer des données de son
composant parent
@Output() : permet a un composant parent de récupérer des données de son
composant enfant
@Output() : permet a un composant parent de récupérer des
données de son composant enfant

104Jaouad Assabbour
Considérez la hiérarchie suivante :
<parent-component>
<child-component></child-component>
</parent-component>
Le <parent-component> sert de contexte pour le <child-component>.
@Input() et @Output() donnent à un composant enfant un moyen de communiquer avec
son composant parent. @Input() permet à un composant parent de mettre à jour les
données dans le composant enfant. Inversement, @Output() permet à l'enfant d'envoyer
des données à un composant parent.

104Jaouad Assabbour
Décorateur @Input
Envoi de données à un composant enfant
Le décorateur @Input() dans un composant ou une directive enfant signifie que la propriété
peut recevoir sa valeur de son composant parent.

105Jaouad Assabbour
Décorateur @Input
Pour utiliser @Input(),
vous devez configurer le parent et l'enfant.
Configuration du composant enfant
Pour utiliser le décorateur @Input() dans une classe de composant enfant,
importez d'abord Input, puis décorez la propriété avec @Input(), comme dans
l'exemple suivant.

Dans ce cas, @Input() décore l'élément de propriété, qui a un type de chaîne, cependant, les propriétés
@Input() peuvent avoir n'importe quel type, tel que nombre, chaîne, booléen ou objet. La valeur de
l'élément provient du composant parent.
Ensuite, dans le modèle de composant enfant, ajoutez ce qui suit :
Jaouad Assabbour

Configuration du composant parent
L'étape suivante consiste à lier la propriété dans le modèle du composant parent. Dans cet exemple, le modèle
de composant parent est app.component.html.
Utilisez le sélecteur de l'enfant, ici <app-item-detail>, comme directive dans le modèle de composant parent.
Utilisez la liaison de propriété pour lier la propriété d'élément de l'enfant à la propriété currentItem du parent.
Dans la classe de composant parent, désignez une valeur pour currentItem :
Jaouad assabbour

Avec @Input() , Angular transmet la valeur de currentItem à l'enfant afin que cet élément
s'affiche en tant que télévision.
Le schéma suivant illustre cette structure :
Jaouad assabbour

Envoi de données à un composant parent
Le décorateur @Output() dans un composant ou une directive enfant permet aux données de circuler
de l'enfant vers le parent.
Jaouad Assabbour

@Output() marque une propriété dans un composant enfant comme une porte par laquelle
les données peuvent voyager de l'enfant au parent.
Le composant enfant utilise la propriété @Output() pour déclencher un événement afin de
notifier le parent du changement. Pour déclencher un événement, un @Output() doit avoir
le type de EventEmitter, qui est une classe dans @angular/core que vous utilisez pour
émettre des événements personnalisés.
L'exemple suivant montre comment configurer un @Output() dans un composant enfant
qui pousse les données d'un <input> HTML vers un tableau dans le composant parent.
Pour utiliser @Output(), vous devez configurer le parent et l'enfant.
Jaouad Assabbour

Configuration du composant enfant
L'exemple suivant présente une <input> où un utilisateur peut entrer une valeur et cliquer sur un
<button> qui déclenche un événement. L'EventEmitter relaie ensuite les données au composant
parent.
Importez Output et EventEmitter dans la classe du composant enfant :
import { Output, EventEmitter } from '@angular/core';
Dans la classe du composant, décorez une propriété avec @Output().
L'exemple suivant newItemEvent @Output() a un type EventEmitter, ce qui signifie qu'il s'agit d'un
événement.
Jaouad Assabbour

Les différentes parties de la déclaration précédente sont les
suivantes :
@Output() : Une fonction décoratrice marquant la propriété comme un moyen pour les
données de passer de l'enfant au parent.
NewItemEvent : Le nom de @Output().
EventEmitter<string> : Le type de @Output().
new EventEmitter<string>() : Indique à Angular de créer un nouvel émetteur
d'événements et que les données qu'il émet sont de type string.
Jaouad Assabbour

Pour plus d'informations sur EventEmitter, consultez la documentation de l'API
EventEmitter.
Créez une méthode addNewItem() dans la même classe de composant :
La fonction addNewItem() utilise @Output(), newItemEvent, pour déclencher un
événement avec la valeur que l'utilisateur tape dans <input>.
Jaouad Assabbour

Configuration du modèle de l'enfant
Le modèle de l'enfant a deux contrôles. La première est une <input> HTML avec une variable de
référence de modèle, #newItem, où l'utilisateur saisit un nom d'élément. La propriété value de la
variable #newItem stocke ce que l'utilisateur tape dans <input>.
Le deuxième élément est un <bouton> avec une liaison d'événement de clic.
L'événement (clic) est lié à la méthode addNewItem() dans la classe du composant enfant. La
méthode addNewItem() prend comme argument la valeur de la propriété #newItem.value.
Jaouad Assabbour

Configuration du composant parent
Le AppComponent dans cet exemple comporte une liste d'éléments dans un tableau et une méthode
pour ajouter plus d'éléments au tableau.
La méthode addItem() prend un argument sous la forme d'une chaîne, puis ajoute cette chaîne au
tableau des éléments.
Jaouad Assabbour

Configurer le modèle du parent
Dans le modèle du parent, liez la méthode du parent à l'événement de l'enfant.
Placez le sélecteur enfant, ici <app-item-output>, dans le modèle du composant parent,
app.component.html.
La liaison d'événement, (newItemEvent)='addItem($event)', connecte l'événement dans
l'enfant, newItemEvent, à la méthode dans le parent, addItem().
L'événement contient les données que l'utilisateur saisit dans <input> dans l'interface
utilisateur du modèle enfant.
Pour voir le fonctionnement de @Output(), ajoutez ce qui suit au modèle du parent :
Jaouad Assabbour

Le *ngFor parcourt les éléments du tableau d'éléments. Lorsque vous entrez une valeur
dans l'<input> de l'enfant et que vous cliquez sur le bouton, l'enfant émet l'événement et la
méthode addItem() du parent envoie la valeur au tableau d'éléments et le nouvel élément
s'affiche dans la liste.
Jaouad Assabbour

Utilisation de @Input() et @Output() ensemble
Utilisez @Input() et @Output() sur le même composant enfant comme suit :
La cible, item, qui est une propriété @Input() dans la classe du composant enfant, reçoit sa valeur de la propriété du
parent, currentItem. Lorsque vous cliquez sur supprimer, le composant enfant déclenche un événement,
deleteRequest, qui est l'argument de la méthode crossOffItem() du parent.
Le schéma suivant montre les différentes parties de @Input() et @Output() sur le composant enfant <app-input-
output>.
Jaouad Assabbour

Le sélecteur enfant est <app-input-output> avec item et deleteRequest étant les propriétés @Input() et @Output()
dans la classe du composant enfant. La propriété currentItem et la méthode crossOffItem() sont toutes deux dans la
classe du composant parent.
Jaouad Assabbour

113Jaouad Assabbour
Directives
destructure

114
Jaouad Assabbour
Directives destructure
Une directive est un élément du framework qui va directement
interagir avec le DOM de la page. Il existe trois types de
directives.
Les directives de structure ont pour rôle est de modifier
l’élément HTML sur lequel elles sont attachées, dans le but
d’ajouter, modifier ou supprimer des éléments HTML.
Les directives structurelles fournies par Angular s’appuient sur
l’élément <ng-template>

115Jaouad assabbour
Directives de structure : ngFor
<ul>
<li*ngFor="letuofusers">{{u.firstName}}</li>
</ul>
*ngFor permet de répéter un template ou un élément html par élément d’une
collection, d'une liste...
<li *ngFor="let elt of list"> {{elt}} </li>
Notre composant first possède un attribut users, qui est un tableau des utilisateurs
en ligne.

Pour avoir le numéro de l'itération, utiliser l’index :
<li *ngFor="let elt of list; let i = index">{{i}} : {{elt}} </li>
Ici index est une variable exportée. Il en existe
d'autres : even, odd, first, last
Tous des booléens qui renvoient vrai ou faux lorsque
l'élément courant est pair, impair, premier, dernier.
Jaouad assabbour

Bonne pratique : TrackBy
TrackBy est une fonction qui permet de tracker dans une directive
ngFor, les changements d’items dans l’itérable (ajout, suppression,
remplacement
d’items...) et de ne re-rendre que les nœuds impliqués dans ces
changements
Coté template il suffit de passer le nom de la fonction
<li *ngFor="let elt of list; trackBy:trackByFunction"> {{i}} : {{elt}} </li>
Jaouad assabbour

Bonne pratique : TrackBy
Coté classe, la fonction trackBy utilisée prend deux
paramètres : l’index et l’élément courant en
paramètre et doit retourner un identifiant unique qui
permet de tracker l’élément (typiquement un id en
base de données)
trackByFunction(index: number, item: any): string {
return item.id;
}
Jaouad assabbour

120
Directives de structure : ngIf
Jaouad assabbour
*ngIf : Si nous voulons instancier le template
seulement lorsqu’une condition est remplie, alors
nous utiliserons la directive ngIf :
<li *ngIf="tab[0]%2 != 0"> {{tab[0]}} est impair </li>
Ici, le template ne sera instancié que si tab est un
élément pair.

Il existe aussi une possibilité d’utiliser else depuis la version 4.0 :
<p *ngIf="true; else elseBlock"></p>
<ng-template #elseBlock></ng-template>
Jaouad assabbour

122Jaouad Assabbour
Directives de structure: ngSwitch
ngSwitch Comme on peut le deviner par son nom, celle-ci permet de switcher entre plusieurs templates
selon une
condition :
<div [ngSwitch]="count">
<p *ngSwitchCase="0"> you have no message </p>
<p *ngSwitchCase="1"> you have one message</p>
<p *ngSwitchDefault>you have some messages</p>
</div>
Comme on peut le voir, ngSwitch prend une condition et les *ngSwitchCase attendent les
différents cas possibles. On a aussi *ngSwitchDefault, qui sera affiché si aucune des autres
possibilités n’est remplie

123Jaouad Assabbour
Directives destructure
Nous avons vu que les directives structurelles s’appuient sur l’élément
<ng-template>
Une autre façon (peu utilisée) d'écrire nos directives serait d'utiliser
directement la balise ng-template et la structure suivante
Notation ng
template
<ng-template ngFor let-user
[ngForOf]="users">
<li>{{user.firstName}}</li>
</ng-template>
Notation simplifiée
<li*ngFor="let user of users">
{{ user.firstName}}
</li>
La notation * est en réalité du sucre syntaxique pour cette notation ci-
dessus. En interne Angular transforme un *ngFor en un élément <ng-
template> qui en globera l'élement templaté. Puis clonera le template
autant de fois que nécessaire.

125Jaouad Assabbour
Directives
d’attributs

126Jaouad assabbour
Directives d’attribut : n g S ty l e
Les directives d’attributs ont pour rôle de modifier l’élément HTML sur lequel elles sont associées.
ngStyle : Nous avons déjà vu que l'on pouvait agir sur le style d’un élément en utilisant le one way binding :
<p [style]="color : red">
<p [style.color]="red">
Si on veut changer plusieurs styles en même temps, on peut utiliser la directive ngStyle :
<div [ngStyle]="{fontWeight: fontWeight, color: color}">Beauty is relative, style is absolute</div>

ngStyle : Nous avons déjà vu que l'on pouvait agir sur le
style d’un élément en utilisant le one way binding :
<p [style]="color : red">
<p [style.color]="red">
Si on veut changer plusieurs styles en même temps, on peut
utiliser la directive ngStyle :
<div [ngStyle]="{fontWeight: fontWeight, color: color}">Beauty is relative, style is
absolute</div>
Jaouad assabbour

128Jaouad assabbour
Directivesdestructure: ngClass
ngClass : De la même façon qu'il est possible d'attribuer une classe via le one
way binding
<p [class]="boldText">
Il est possible d'affecter plusieurs classes à un élément via la directive de
structure ngClass
<div [ngClass]="{boldText: isBold(), color: textColor()}">Style is absolute, but class is
eternal</div>

130Jaouad Assabbour
Enrésumé...

Jaouad assabbour 131
Enrésumé
Le système de template d’Angular nous propose une syntaxe puissante pour
exprimer les parties dynamiques de notre HTML Elle nous permet d’exprimer du
binding de données, de propriétés, d’événements, et des considérations de
templating avec des symboles propres :
{{}} : pour l’interpolation
[] : pour le binding de propriété
() : pour le binding d’événement
# : pour la déclaration de variable
* : pour les directives structurelles

132Jaouad assabbour
Pipe

133Jaouad assabbour
Pipe
Les données brutes n’ont pas la forme exacte que l’on voudrait afficher dans la
vue. On a envie de les transformer, les filtrer, les tronquer, etc.
Angular fournit des classes spécialisées : ils se nomment pipes (tuyaux)
décorateur @Pipe Pour les utiliser dans le template :
{{ maVariable | nomPipe }}
Il existe un certain nombre de pipes prédéfinis. Nous allons en voir
certains.

134 Jaouad assabbour
Pipes texte
Uppercase :
{{'Hello World' | uppercase}}
> HELLO WORLD
lowercase :
{{'Hello World' | lowercase}}
> hello world
titlecase :
{{'hello world' | titlecase}}
> Hello World

135Jaouad Assabbour
Pipe date et currency
c u r r e n c y :
{ { 5 0 | c u r r e n c y : ' E U R ' : ' s y m b o l ' : 0 . 0 - 0 : ' f r ' } } = > 5 0 . 0 0 €
L a l i s t e d e s o p t i o n s d e s m o n n a i e s : h t t p s : / / a n g u l a r . i o / a p i / c o m m o n /
C u r r e n c y P i p e
d a t e : { { d a t e | d a t e : ' d M M M y ' } } = > 1 J a n 2 0 2 0
L a l i s t e d e s o p t i o n s d e s d a t e s :
h t t p s : / / a n g u l a r . i o / a p i / c o m m o n / D a t e P i p e
I l e s t a u s s i p o s s i b l e d e c h a î n e r l e s p i p e s ( a t t e n t i o n l ’ o r d r e a s o n
i m p o r t a n c e )
{ { m a D a t e | d a t e : ' d M M M y ' | u p p e r c a s e } } = > 1 J A N 2 0 2 0

136Jaouad Assabbour
Pipejson
JSON :{{ data | json }}
json est un pipe pas tellement utile en production, mais bien pratique pour le
débug. Ce pipe applique simplement JSON.stringify() sur les données
Si on a un tableau de users et qu’on veut rapidement voir ce qu’il contient :

137Jaouad assabbour
P i p e s l i c e
Slice:
{{ data | slice : start : finish }}
slice prend deux paramètres : l'indice de départ et l'indice
d'arrivée (exclu)
Pour n'afficher que les 2 premiers éléments d'un tableau :
{{ tab | slice : 0 : 2 }}
Slice fonctionne aussi avec les chaines :
{{ 'helloworld' | slice : 0 : 5 }}
>hello

Slice: {{ data | slice : start : finish }} Comme on peut utiliser slice dans n’importe quelle
expression, on peut aussi l’utiliser avec NgFor
Le composant ne créera ici que deux <li>, pour les deux
premiers users, parce qu’on a appliqué slice à la
collection.
Jaouad assabbour

139Jaouad assabbour
Créer son propre Pipe
Pour créer un pipe
ng generate pipe[nompipe]
ou
ng g p[nom-pipe]
Le pipe implémente l’interface PipeTransform, ce qui nous
amène à écrire une méthode tranform() qui doit retourner la
valeur transformée

Pour faire appel à un pipe existant,il faut l'importer et
utiliser l'injection de dépendance. On utilise ensuite sa
méthode transform avec la valeur à transformer,et les
éventuels paramètre supplémentaires.
Jaouad assabbour

Pipe async
Un autre pipe fort utile est le pipe async.
async prend en entrée une promise ou un observable
et en affiche le résultat
L’intérêt est de souscrire à un Observable ou une
Promise et de retourner la dernière valeur émise. Le
pipe async se désabonne automatiquement à la
destruction du composant.
{{ data | async }}
Jaouad assabbour 142

144Jaouad assabbour
Injection
dedépendance

145Jaouad Assabbour
Injection
dedépendance
L’injection de dépendances est un design pattern bien connu
Un composant peut avoir besoin de faire appel à des fonctionnalités qui sont
définies dans d’autres parties de l’application (un service, par exemple)
C’est ce que l’on appelle une dépendance : le composant dépend du service
Au lieu de laisser au composant la charge de créer une instance du service, l’idée
est que le framework crée l’instance du service lui-même, et la fournisse au
composant qui en a besoin

Cette façon de procéder se nomme l’inversion de contrôle
Cela apporte plusieurs bénéfices :
• Simplicité. Vous n'avez plus à vous soucier du comment instancier les modules
que vous utilisez.
• Fiabilité. Lorsque votre module est chargé, vous avez la certitude que toutes ses
dépendances sont chargées et que
vous avez la possibilité de les utiliser.
• Réutilisabilité. Lorsque vous développez des services, il y a fort à parier que
vous souhaiteriez pouvoir réutiliser ce module.
• Tests. Si le module que vous souhaitez tester possède 10 dépendances, il est
assez embêtant d'avoir à instancier les 10 modules afin de pouvoir juste tester
notre module.
Jaouad Assabbour

Avec TypeScript, c’est très simple de déclarer une
dépendance dans un composants ou services, il suffit
d’utiliser le système de typage.
Par exemple nous voulons écrire un composant
UserProfile qui utilise le service User.
Jaouad Assabbour

Angular récupérera le service UserService et l’injectera dans le
constructeur
Quand le composant est utilisé, son constructeur sera appelé, et le
champ userService référencera le service UserService

Et coté UserService :
Pour indiquer à Angular que ce service a lui-même
d'éventuelles dépendances, on doit lui ajouter un décorateur
@Injectable()
Jaouad assabbour

@Injectable() est un décorateur un peu particulier. Il ne permet pas l’injection à
proprement parlé, mais plutôt d’initialiser un contexte de détectabilité.
Si vous injectez dans un de vos services ( sans ce décorateur) un autre service, le moteur
d'injection retournera une erreur.
Angular conseille de toujours mettre cette annotation sur un service même si vous n'utilisez
pas les injections dans les premiers développements de votre service afin d'éviter de se
poser la question plus tard.
Jaouad assabbour

Et coté template ?
UserService devient une variable utilisable dans mon template. Et je
peux accéder à sa propriété user.
Je peux éventuellement créer une nouvelle propriété dans mon
composant pour raccourcir la notation.
Jaouad assabbour

Injection
dedépendance
Avant d'utiliser UserService, nous avons toute fois besoin de
"l’enregistrer" ,pour le rendre disponible à l’injection.
Pour les versions <Angular6 : Une façon simple était
d’utiliser l’attribut providers du décorateur @NgModule dans
le module principal
Jaouad Assabbour 152

153
Injection
dedépendance
Jaouad assabbour
Dans les versions > 6 d'angular ,providedIn :'root' dans
le décorateur @Injectable du service fait office de
déclaration

154Jaouad assabbour
Injecteur shiérarchiques
Les providers déclarés dans l’injecteur racine (ou avec
providedIn : 'root') sont des singletons disponibles pour
tous les composants qui en font la demande.
On peut toute fois déclarer des dépendances à
d’autres niveaux que le module racine.
Le décorateur @Component peut recevoir une autre
option de configuration, appelée providers
Cet attribut providers peut recevoir un tableau avec une
liste de dépendances, comme nous l’avons fait avec
l’attribut providers de @NgModule

C’est pratique si on veut des
composantsparfaitement encapsulés qui déclarent
tout ce dont ils dépendent.
Providers [UserService]
est une syntaxe abrégée de
providers:[{ provide:UserService, useClass: UserService}]
Jaouad assabbour

161Jaouad Assabbour
Services

162Jaouad assabbour
Services
Un service est :
•une classe TypeScript décorée par un @Injectable.
•un singleton: La même instance unique sera injectée partout.
Cela enfait le candidat idéal pour partager un état parmi plusieurs
composants séparés
•souvent un intermédiaire avec le back-end
•injectable dans les classes qui enont besoin
•peut avoir ses propres dépendances

Bonne pratique
• Laisser les services gérer le traitement des données et la logique
métier
• Laisser les composants gérer l’affichage des données et les
interactions avec le DOM
Jaouad assabbour

Pour créer un service :
ng generate service [nom-service]
Le fichier créé sera de forme [nom-service].service.ts

Sans ce décorateur
@Injectable, le framework ne
pourra pas faire l’injection de dépendances si
mon service dépend d'autres services
Imaginons que notre service a une
dépendance vers HttpClient pour récupérer
des Users depuis une API
Nous allons donc devoir ajouter un constructeur avec le service HttpClient en argument,
et ajouter ledécorateur @Injectable() sur la classe Angular expose un service Title qu’on
peut injecter, et propose un getter et un setter, permettant de modifier le titre du document
html.

Routing
173
Jaouad assabbour 174
176

178Jaouad assabbour
Router Module
Jusqu'ici, nous avons déclaré tous nos composants dans le template du composant
principal. Mais ça n'est pas toujours ce que l'on veut faire.
On va généralement plutôt définir un chemin d'accès (une URL) pour un composant donné.
Et le composant sera affiché si son chemin d'accès apparait dans la requête http.
D'où le routage

179Jaouad assabbour
Router Module
Dans Angular, les Routes sont un tableau d’objets possédant les attributs suivants :
• path : URL qui déclenchera la navigation
• component : composant sera initialisé et affiché
A noter que les routes dépendent du module RouterModule. C’est un module optionnel qu'il
faut inclure dans le module racine car il n’est donc pas inclus par défaut.

RouterModule a deux méthodes statiques qui prennent en paramètre un
tableau de Routes
•.forRoot(tableau) : pour les routes du module principal
•.forChild(tableau) :pour les autres sous-modules inclus dans le
module principal

180Jaouad assabbour
Organisation des routes
constappRoutes:Routes=[
{path:'login',component:LoginComponent},
{path:'',component:HomeComponent}
]
Il faut bien comprendre également que le router va
lire les routes de haut en bas et va tenter de matcher
(via une regex) la première route à correspondre au
path emprunté.
Si par exemple on spécifie un path vide (l’accueil) en
premier, ce dernier sera matché à tous les coups.
Une bonne pratique est donc d’organiser les routes
des plus spécifiques aux plus générales.

181Jaouad assabbour
Organisation des routes
constappRoutes:Routes=[
{path:'',component:HomeComponent,pathMatch:'full'},
{path:'login',component:LoginComponent}
]
Une autre solution consiste à ajouter la propriété path Match: 'full’
Dans ce cas, Angular vérifie qu’il y a une correspondance exacte entre la route et l’url
empruntée.

Les URL saisies auront la forme
suivante :
•localhost:4200/address
•localhost:4200/person
{ enableTracing: true } : pour le
débogage, elle permet de garder une
trace de la recherche d’un
chemin dans la console

183 Jaouad Assabbour
Router O u t l e t
Il faut également utiliser un tag
spécial dans le template du
composant principal pour activer le
routing:
<router-outlet>
pour que les composants routés
soient inclus dans la page.
Lorsque le module de routeur
active une route, le composant
de la route est inséré dans la
page à l’emplacement marqué
par la directive <router-outlet>
Enfin, créeons un petit menu de navigation
pour tester le routing

184 Jaouad assabbour
Routing M o d u l e
Une meilleure pratique est de déclarer notre tableau de
routes dans un fichier séparer et d'appeler en suite ce fichier dans
notre module racine:
ng generate module routing-m=app
•Génère un module qui s'appelle app-routing
•--module=app: pour l'enregistrer dans lemodule
racine

Avant
app.module.ts
Après
app.module.ts
app.routing.module.ts
Jaouad assabbour

187
Router Link
Jaouad assabbour
Les liens avec un attribut href
entraînent un rechargement de
la page, et redémarrent
l’application.
Le but d’Angular est
justement d’éviter ces
rechargements
Solution: remplacer l'attribut
href de nos liens par un
attribut routerLink

La directive RouterLink peut être utilisée avec la directive
Router LinkActive, qui peut ajouter une classe CSS
automatiquement si le lien pointe sur la route courante
routerLinkActive=classname nous permet d'attribuer une classe à
l'item actif.
[routerLinkActiveOptions] = '{exact:true}' Pour n'activer le
routerLink que si laroute matche totalement le lien
Jaouad assabbour

Jaouad assabbour
189
Router Navigate
Il est aussi possible de naviguer depuis le code, en utilisant le service
Router et sa méthode navigate().
C’est souvent pratique quand on veut redirige rnotre
utilisateur suite à une action :
La méthode prend en paramètre un tableau dont le premier
élément est le chemin vers lequel on souhaite rediriger
l’utilisateur (ici, vide pour l'accueil)

191Jaouad assabbour
Routing
Il est é g a l e m e n t p o s s i b l e d’avoir d e s paramètres d a n s l’U R L , et c’est très pratique pour d é f in i r des URL
sd y n a m i q u es.
Il existe deux façons de gérer les paramètres dans l'URL :
•/chemin/param1/param2 : lorsque les paramètres sont
obligatoires
•/chemin?var1=value1&var2=value2 : lorsque les p a r a m è t r es s o n t
optionnels
Et deux objets differents permettant de récupérer les valeurs :
•paramMappour/chemin/param1/param2
•queryParamMappour/chemin?var1=value1&var2=value2

192Jaouad assabbour
Routing-Paramètres obligatoires
Pour récupérer une URL de forme
user/param1/param2, il faut :
•Aller dans le composant concerné
•Faire une injection de dépendance avec la classe
ActivatedRoute en paramètre de constructeur
•Utiliser un des objet de la classe
ActivatedRoute dans la méthode
ngOnInit()
•ObjetparamMap (solutionaveclesobservables)
•Objetparams(solutionaveclessnapshots)

Routing-Paramètres obligatoires
Par exemple, on pourrait afficher une page de détail pour un utilisateur, et
cette page aurait une URL significative comme users/id-du-user/nom-
du-user
Pour cela on définit une route dans la configuration avec un (ou
plusieurs) paramètre(s) dynamique(s)
On peut alors définir des liens dynamiques avec routerLink:
Jaouad assabbour 193

Routing- snapshot
194Jaouad assabbour
Et bien sûr on peut récupérer ces paramètres facilement dans
le composant cible
Grâce à l’injection de dépendances, notre composant
UserComponent reçoit un objet du type ActivatedRoute
Cet objet peut être utilisé dans ngOnInit, et a un champ bien
pratique : snapshot qui contient les paramètres de l’URL dans paramMap

195
Routing- observable
Jaouad assabbour
Il existe aussi une façon de nous abonner aux changements de
paramètre avec un observable
Cet observable est appelé paramMap
Supposons que notre composant a un bouton "Suivant" pour aller
sur le user suivant.
Quand l ’ u t i l i s a t e u r c l i q u e r a s u r l e bo u t o n,l’URL va h a n g e r de
/user/1à/user/2 par exemple.
Le routeur va alors réutiliser notre instance de composant: cela veut
dire que ngOnInit ne sera pas appelée à nouveau!
Dans ce cas, si on veut que notre composant se mette à jour nous
devons utiliser l’observable paramMap

Nous nous abonnons à l’observable offert par ActivatedRoute
Maintenant, à chaque fois que l’URL changera de /user/1à/user/2 par
exemple, l’observable paramMap va émettre un événement , et nous
pourrons récupérer le bon use r à afficher à l’écran

197
Jaouad assabbour
Routing- snapshot vs o b s e r v a b l e
Snapshot
route statique
Observable
route dynamique

198
Jaouad assabbour
Routing-Paramètres optionnels
Pour récupérer une URL de forme
user?param1=value1&param2=value2 , il faut :
•Aller dans le composant concerné (ici,userProfile)
•Faire une injection de dépendance avec la classe
ActivatedRoute en paramètre de constructeur
•Utiliser un des objet de la classe
ActivatedRoute dans la méthode
ngOnInit()
•Objet queryParamMap (solution avec les
observables)
•Objet queryParams(solution avec les snapshot)

Par exemple,on pourrait afficher une page de détail pour un
utilisateur, et cette page aurait une URL significative comme
users?id=id-du-user
Pour cela on déclare la route sans paramètres
On peut alors définir des liens dynamiques avec routerLink
et queryParams:

Et pour accéder aux paramètres (solution avec les
observables)

202

constappRoutes:Routes=[
{path:'404',component:NotFoundComponent},
{path:'**',redirectTo:'/404'},
];
Route404
Il peut être utile de créer un composant spécifique
pour les routes qui n’existent pas.
Cela sefait avec un path « wildcard» : ** qu’il faut
placer à la fin du tableau de routes.
Ce path doit rediriger vers un composant qui a pour but
d’indiquer à l’utilisateur qu’il est sur une route inexistante
Jaouad assabbour 203

205Jaouad assabbour
Routeshiérarchiques
Les routes peuvent avoir des routes filles.
Cela peut être utile pour plusieurs raisons :
•appliquer un template commun à plusieurs routes
•appliquer des guards à plusieurs routes à la fois
•appliquer des resolvers à plusieurs routes à la fois

Lorsque le routeur active une route,le composant de la route est inséré dans
l a p a g e à l’emplacement m a r q u é p a r l a d i r e c t i v e r o u t e r-outlet.Ce mécanisme
peut aussi être utilisé par les composants imbriqués
Supposons quel’on veuille créer une page complexe pour afficher le profil d’un
utilisateur.
•Cettepage afficherait le nom et le portrait de l'utilisateur dans sa partie
supérieure, et afficherait des onglets dans sa partie inférieure: un onglet
pour les posts et partages, un autre pour les pages et groupes likés,un
troisième pour ses amis...
•On veut que chaque onglet ait sapropre URL, afin de pouvoir créer des
liens directs vers chacun d’eux
•Mais on veut aussi éviter de recharger le user,et de répéter son nom et
son portrait sur chacun des trois composants correspondant aux trois onglets

La solution est d’utiliser un router-outlet dans le template du
UserProfileComponent, et de définir une route mère pour le user :
Lorsqu’on navigue vers u s e r / 4 2 / l i k e s, par exemple, le routeur insère le
UserProfileComponent à l’emplacement marqué pa rle
< r o u t e r – o u t l e t > principal, dans le composantracine
Le template du UserProfileComponent, en plus du nom et du portrait du user,
contient lui aussi un <router-outlet> C’est là que le composant de la route fille
(UserLikesComponent) est inséré

...
<router-outlet>
...
<router-outlet>
...
user-likes.component.html
user-profile.component.html
app.component.html

Routes hiérarchiques
En revanche, si on navigue vers user/42, le composant user-profile
sera affiché, mais aucun des trois sous-composants ne le sera...
Tâchons d’afficher plutôt les posts par défaut. Il suffit pour cela d’ajouter
une route fille ,avec un chemin vide, et qui redirige vers la route user-likes:
Jaouad assabbour 209

210Jaouad assabbour
Routes hiérarchiques
Au lieu de rediriger, on peut aussi afficher les posts
directement àl’adresse u s e r / 4 2.
Là aussi, il suffit d’utiliser un chemin vide :

211Jaouad assabbour
Routes-g u a r d s
Certaines routes de l’applicationne devraient pas
être accessibles à tous.
L’utilisateur est-il authentifié ?
A-t-il les permissions nécessaires ?...
Il existe 4 types de guards :
•CanActivate
•CanActivateChild
•CanLoad
•CanDeactivate

CanActivate : lorsqu’un t e l g u a r d est a p p l i q u é à une
route,ilpeut empêcher l’activation de la route.
Il peut aussi avoir un effet de bord, comme par
exemple rediriger vers une autre route. C’est ce qui permet
d’afficher une page d’erreur, ou de naviguer vers la page de
connexion lorsqu’un utilisateur anonyme tente
d’accéder à u n e p a g e q u i r e q u i e r t une authentification.

CanActivateChild: Ce guard fonctionne sur le même
principe que CanActivate, sauf qu'il peut empêcher
les activations des enfants de la route sur lequel il est
appliqué.
Cela peut être utile, par exemple, pour empêcher
l’accès à de nombreuses routes d’un seul coup ,en fonction
de leur URL

CanLoad: ce guard peut être utilisé sur une route qui
a un attribut loadChildren.
Cet attribut permet de télécharger un module
applicatif à la demande (lazy loading), contenant des
routes filles.
Ce guard va plus loin que les deux précédents en
empêchant le téléchargement du fichier JavaScript
lui-même.

CanDeactivate: ce guard est différent des trois
autres. Il est utilisé pour empêcher de quitter
laroute actuelle.
Cela peut être utile pour, par exemple, demander
une confirmation avant de quitter une page
contenant un long formulaire

Voici comment appliquer un guard CanActivate à
une route. Les trois autres types sont appliqués de
manière similaire :
Dansl’exemple c i-dessus,L o g g e d I n G u a r dest un
guard Angular

Pour créer un guard :
ng generate guard nom-guard
Et préciser ensuite le type d'interface à implémenter

Dans la pratique, le code généré est très similaire à
celui d'un service, sauf qu'il n'a pas de constructeur et
qu'il implémente une ou plusieurs des interfaces
choisies.
Jaouad Assabbour

Notre guard doit implémenter l’interface
CanActivate.
Elle doit simplement à décider si la route peut être
activée ou non (en vérifiant si l’utilisateur est authentifié
ou non), et à retourner un boolean, une
Promise<boolean>, ou un Observable<boolean>
Le routeur naviguera vers la routes i la valeur
retournée est true, ou si la promesse retournée est
résolue à t r u e , o u s il’observable retournéé m e t t r u e.
Jaouad Assabbour

Voilà à quoi pourrait ressembler le LoggedInGuard :
Jaouad Assabbour

Les routes hiérarchiques, combinées aux routes à chemin vide, sont très pratiques
pour appliquer un guard sur de nombreuses routes d’un seul coup.
Par exemple, si on veut que les routes affichant des utilisateurs, la modification de
profiletlesamisnesoientaccessiblesqu’auxutilisateursauthentifiés,aulieude:
on peut introduire une route mère avec un chemin vide, et sans composant.
Cette route ne consommera aucun segment d’URL , et n’activera aucun composant , mais ses
guards seront appelés chaque fois qu’on navigue vers l’une de s es routes filles:
.
Jaouad assabbour

223Jaouad assabbour
Programmation
réactive
Introduction à RXJS et aux observables

224Jaouad assabbour
Programmationréactive
La programmation réactive est un paradigme de
développement asynchrone. Une autre façon de
construire une application avec des événements, et d’y
réagir.
Angular est construit sur de la programmation réactive :
•répondre à une requête HTTP
•lever un événement spécifique dans un denos
composants
•gérer un changement de valeursdans un de nos
formulaires
Autant d’éléments qui demandent de réagir à des
événements.

225Jaouad assabbour
RxJS
Angular utilise la librairie RXJS (Reactive extensions
for JavaScript) pour gérer la programmation réactive
Un flux est une séquence ordonnée d’événements. Ces
événements représentent des valeur ou deserreurs
et des terminaisons
Nous devons nous abonner (subscribe) à ces flux,
c’est à dire définir un objetcapablede gérer cestrois
possibilités. Cet objet sera appelée un observer, et le
flux, un observable

226Jaouad assabbour
Programmation réactive
Pour simplifier les choses, on peut imaginer qu’un
observable est un poste de radio.
Le flux, un morceau, dont chaque note représente
des valeurs. Ce morceau va éventuellement prendre
fin (terminaison) ou pourquoi pas, une erreur de
fréquence peut survenir (error).
Et l’observer est l’auditeur qui réagit à ces
événements.

227Jaouad assabbour
Différencesaveclespromises
Ils sont très similaires aux promises que nous avons
vu plus tôt, car ils gèrent tous deux des valeurs
asynchrones.
Mais également très différents.
•Dans une promise, la callback de succès ne peut
s’exécuter qu’une seule fois.
•A la différence d’une promise, un observer n’est pas à usage
unique : i lcontinuera d’écouter jusqu’à ce
qu’il reçoive un é v é n e m e n t d e t e r m i na i s o n (ou si on force
son désabonnement). La callback desuccès peut
s’exécuter à plusieurs r e pr ises

228Jaouada assabbour
Différences avec les t a b l e a u x
Les observables sont aussi très similaires à des
tableaux. Un tableau est unecollection de valeurs,
comme un observable. Un observable ajoute juste la
notion de valeur reportée dans le temps :
•dans un tableau,toutes les valeurs sont disponibles
immédiatement,
•dans un observable, les valeurs viendront plus tard,
par exemple dans plusieurs minutes

229Jaouad assabbour
Observable / Observer?
Observable: une fonction retournant un flux de
valeurs à un observer de manière synchrone ou
asynchrone. Un observable s'éxécute s'il y a un
observer et un abonnement (avec la méthode
subscribe)
Observer: un objet qui réagit à un observable pour
recevoir les changements et exécuter une suite de
code.

230
Observable
aouad assabbour
observable:Observable<number>=newObservable(
(observer)=>{observer.next(1);o
bserver.next(2);observer.next(
3);observer.complete();
}
);
Pour définir un observable, on peut le faire
directement en instanciant un objet de la classe
Observable de RxJS. L’observable prend alors en
paramètre une fonction qui indique quelles données
seront transmises àl’observer

231
Observer
aouad assabbour
observer:Observer<number>={
next:
(value)=>console.log(value),error:
(err)=>console.error(err),complete:
()=>console.log('DONE!'),
};
Un observer est un objet possédant trois callbacks :
•next (requis) : callback de succès appelée successivement
à chaque valeur envoyée par l’observable
•error (optionnel) : callback d’erreur qui s’exécute lorsqu’une erreur
est produite
•complete(optionnel):callbackquis’exécuteàlafindutraitementdel’observable

232
aouad assabbour
Souscription
Une souscription s’obtient avec la méthode subscribe de
l’observable. Cette méthode prend en paramètre un observer
etre tourne un objet subscription, qui possède une
méthode un subscribe pour sedésabonner.
Bonnepratique: se désabonner systématiquement d’un
observable d a n s l e NgOnDestroy p our éviter les fuites mémoire.
subscription:Subscription=this.observable.subscribe(this.observer);
this.subscription.unsubscribe()

233aouad assabbour
Opérateurs de création d’observables
Ilexistede très nombreuses méthodes quipermettentde créer des
observables dans RxJS. En voici quelques unes:
•interval (period: number) qui retourne un observable qui
ém e t un compteur qu i s’ in c ré m en te en fonction de period
•of(…values) qui é m e t l es valeurs p a s s é e s ena r g u me n t
•from(iterable) qui émet les valeurs de l’itérable

234
aouad assabbour
Subject
Les subjects, sont un autre type
d’Observable.
Leur principale différence est que,
contrairement aux observables
classiques, ils vont émettre des données «
à chaud » à leur création,sans attendre
qu’un observer ysubscribe.
Les messages émis avant la
souscription ne seront pas observés.

constsubject=newSubject();subject.next('me
ssagedusubjectnonlu');subject.subscribe(v=
>console.log(v));subject.next('messagedusu
bjectlu');
Une autre différence fondamentale entre Observable et
Subject ,c’est que le subject agit comme un observable,
mais aussi comme un observer.
C’est-à-direqu’il possède ses propres méthodes next,
error et complete et n’est, de fait, pas obligé d epasser par
un observer
aouad assabbour

236
aouad assabbour
Différence subjects / observables

237aouad assabbour
Autres t y p e s de s u b j e c ts
En plus des Observables et
des Subjects, il existe deux
autres grands types de
Subjects que nous
évoquerons :
Les BehaviorSubject qui
rejouent la dernière valeur
manquée avant la
subscription
Les ReplaySubject : qui
rejouent toutes les valeurs
manquées avant la
subscription

238aouad assabbour
Pipable Operators
En plus des opérateurs déjà vus, RxJS dispose aussi
de nombreux opérateurs que l’on peut chainer à nos données
pour les transformer, les filtrer, les combiner…
Un Pipeable Operator est une function qui prends un
Observable en entrée et retourne un autre observable.

239aouad assabbour
Pipable Operators
obs=from([1,2,3,4,5]);piped=ob
s.pipe(
map((val)=>val+10),
map((val)=>valxval)
);
subscribe=piped.subscribe((val)=>console.log(val));
On appelle ces opérateurs ‘ pipables’ car on les ‘tuyaute’ à un Observable à
l’aide d’une méthode pipe.
La méthode pipe peut prendre en paramètres autantd’opérateurs que
nécessaire
Ici on pipe notre observable avec deux opérateurs map

Il existe plusieurs Pipables Operators que l’on peut
catgoriser en plusieurs familles. Citons :
Les opérateurs de combinaison qui servent à
combiner plusieurs observables entre eux
Les opérateurs de filtre qui servent à filtrer des
valeurs émises par un observable
Les opérateurs de transformation qui modifient les
valeurs émises par un observable

Citons par exemple :
• tap : pour effectuer des effets de bord sans modifier
l’observable en entrée (pour des logs) tap(val =>
console.log(val))
• map : pour appliquer une fonction à toutes les valeurs émises
par un observable map(val => val +1)
• pluck : lorsqu’un objet est émis, permet de choisir quel
champ retourner
pluck(‘firstName’)

Citons par exemple :
•throttleTime: qui permet de n’observer qu’ à une
fréquence donnée, les valeurs émises entre temps
sont ignorées
throttleTime(3000)
•debounceTime : quin’observe que si un c e r t a i n temps
s’est éc o ul é entre de ux valeurs é m i s e s
debounceTime(3000)
Jaouad assabbour

Citons par exemple :
•distinct : qui ignore les valeurs émises en double
distinct()
•filter: qui ignore les valeurs émises qui ne
respectent pas la condition
filter(val=>val>0)
244
Jaouad assabbour

245Jaouad assabbour
Life cycle Hooks

246Jaouad assabbour
Life Cycle Hooks
Au cours du développement d’une application Angular, il est
important d’être conscient du cycle de vie de cette application.
L’application étant composée de composants, cela passe alors
principalement par le cycle de vie des composants en soi.
Le cycle de vie d’un composant est géré par Angular, et c’est
donc Angular qui s’occupe de créer le composant, puis de le
rendre avec ses propriétés, et enfin de le détruire lorsque c’est
nécessaire.
Angular fournit des hooks sur les quels le développeur peut se
brancher pour interagir avec le cycle de vie d’un composant, le
terme exact étant lifecycle hooks.

247Jaouad assabbour
Life cycleHooks
Il y a plusieurs phases accessibles, ce sont les hooks :
•ngOnChanges est appelé lorsqu’un input est défini ou
modifié. La méthode fournit un paramètre possédant
lesvaleursavantet après modifications des inputsconcernés.
•NgOnInit est appelé une seule fois après le premier
ngOnChanges . I l perme t d ’ in i t i a li s e r l e c o m p os a n t o u l a
directive après que les premiers bindings soient faits,les
i p u ts sont chargés dans le composant à cemoment-là.
•NgOnDestroy est appelée quand le composantest
supprimé. Utile pour y faire du nettoyage

•ngDoCheck est légèrement différente. Elle
sera appelée à chaque cycle de détection de
changements, e n t e n an t compte d’une c o n di t i o nq u e
nous aurons définie
•ngAfterContentInit est appelée quand tous les
contenus du composant ont été vérifiés pour la
première fois
•ngAfterContentChecked est appelée quand tous
les contenus du composant ont été vérifiés, même s’ils n’ont
pas changé
Jaouad assabbour

•ngAfterViewInit est appelée quand les vues du
composant et de ses enfants sont initialisées et tous
les bindings du template ont été vérifiés pour la
première fois
•ngAfterViewChecked est appelée quand tous les
bindings du template ont été vé ifiés , même s’ils n’ont
pas changé. Cela peut être utile si le composant
ou la directive attend qu’un élément particulier soit
disponible pour en faire quel que chose, par
exemple mettre le focus dessus
Jaouad assabbour

251Jaouad assabbour
Tester les Life cycle Hooks
exportclassLifecycleComponentimplementsOnInit,OnChanges,OnDestroy,AfterContentChe
cked,AfterContentInit,AfterViewChecked,AfterViewInit,DoCheck{
_count:number;
getcount():number{
returnthis._count;
}
@Input()
setcount(val:number){
console.log('countsettercalledwithvalue:'+val);
this._count=val;
}
constructor()
{console.log('Constructorcalled,countvalueis:'+this.count);}ngOnInit():void{console.
log('ngOnInitcalled,countvalueis:'+this.count);}ngOnChanges(changes:SimpleChanges):v
oid{
console.log('ngOnChangescalledwithchanges:',changes);
}
ngDoCheck(){console.log('ngDoCheckcalled');}
ngAfterContentChecked():void{console.log('ngAfterContentCheckedcalled');}ngOnD
estroy():void{console.log('ngOnDestroycalled');}ngAfterContentInit():void{cons
ole.log('ngAfterContentInitcalled');}ngAfterViewChecked():void{console.log('ng
AfterViewCheckedcalled');}ngAfterViewInit():void{console.log('ngAfterViewInitc
alled');}
}

252Jaouad assabbour
Variables de
template

253Jaouad assabbour
Variables l o c a l e s
Les variables de template, ou variables locales sont des variables
qu’on peut déclarer dynamiquement dans le template avec la notation #
Supposons qu’on veuille afficher la valeur d’un input :
Avec la notation #, on crée une variable locale name qui référence
l’objet HTMLInputElement du DOM.
Cette variable locale peut être utilisée n’importe où dans le
template.
Comme HTMLInputElement a une propriété value, on peut l’afficher
dans une expression interpolée
Attention l'événement keyup est ici obligatoire, même s'il n'appelle
rien.

Un autre cas d’usage des variables locales est l’exécution d’une action sur
un autre élément
Par exemple, on peut vouloir donner le focus à un élément quand on clique
sur un bouton
La méthode focus() est standard dans l’API DOM, et on peut maintenant
en bénéficier
Avec une variable locale en Angular, c’est simple :

255Jaouad assabbour
Formulaires
Comment gérer efficacement les formulaires

256Jaouad assabbour
Formulaires
On peut écrire un formulaire de 2 façons :
•Pilotée par letemplate : en utilisant seulement des
directives dans le template : Utile pour des formulaires
simples, sans trop de validation
•Pilotée par le code : en écrivant une description du
formulaire dans le composant : On utilise ensuite des
directives pour lier ce formulaire aux
inputs/textareas/selects du template . Utile pour générer
desformulairesdynamiquement

257Jaouad assabbour
Template driven
forms
Les formulaires pilotés par le template

258Jaouad assabbour
Formulaires p i l o t é s p a rl e template
<form>
<inputtype="email"name="email">
<inputtype="password"name="password">
<buttontype="submit">Valider</button>
</form>
Prenons un cas d’utilisation en le codant de chacune
des deux façons, et étudions les différences
On va écrire un formulaire simple, pour enregistrer
de nouveaux utilisateurs dans notre application
Comme on a besoin d’un composant de base pour
chacun des cas d’utilisation, commençons par celui-ci

Notre formulaire étant piloté par le template, c’est d’ici que nous
allons gérer l’essentiel de la validation qui se fait comme en html
classique, avec des attributs sur nos
champs tels que :
• required : le champ ne peut être vide
• minlength / maxlength : le champ doit avoir un certain
nombre de caractères
• min / max : le nombre entré doit être entre bornes
Jaouad assabbour

<form>
<inputtype="email"name="email"ngModelrequired>
<inputtype="password"name="password"ngModelrequiredminlength="5">
<buttontype="submit">Valider</button>
</form>
Il nous faut aussi enregistrer nos
champs auprès d’Angular avec directive
ngModel. Ici pas besoin d’aller jusqu’au
two-way-binding, nous verrons pourquoi
Jaouad assabbour

<form(ngSubmit)="onSubmit(userForm)"#userForm="ngForm">
<inputtype="email"name="email"ngModelrequired>
<inputtype="password"name="password"ngModelrequiredminlength="5">
<buttontype="submit">Valider</button>
</form>
Enfin, nous devons ajouter une variable de référence à notre
formulaire pour pouvoir effectuer des traitements dans le code,
ainsi qu’un event ngSubmit associé à une fonction handler
pour gérer la soumission :
Notez que nous associons la référence #userForm à
ngForm. Et que nous passons notre formulaire en
paramètre du handler submit Passons dans le code
maintenant
Jaouad assabbour

262Jaouad assabbour
onSubmit(userForm:NgForm)
{console.log(userForm.value
)userForm.reset()
}
Il nous faut gérer la méthode onSubmit appelée dans
le template. Cette méthode va simplement loguer les
données de notre formulaire et remettre notre
formulaire à zéro :
NgForm est une directive qui sert à binder les
formulaires pilotés par le template et à tracker ses
valeurs et son statut de validation

263Jaouad assabbour
Il possède entre autre les propriétés suivantes :
• submitted : boolean vrai si le formulaire a été soumis
• value : objet contenant toutes les valeurs soumises
• valid : vrai si les champs sont valides
• invalid : l’inverse de valid
• errors : la liste des erreurs
• pristine : vrai si aucune donnée n’a été saisie
• dirty : l’inverse de pristine
• touched : vrai si un champ à recu le focus
• untouched : l’inverse de touched

A noter que, quelle que soit la méthode (template ou
code), Angular va attribuer les classes suivantes à
tous les champs des formulaires, permettant de les
styler de manières différentes
State Class if true Class if false
The control has
been visited.
ng-touched ng-untouched
The control's
value has
changed.
ng-dirty ng-pristine
The control's
value is valid.
ng-valid ng-invalid

266Jaouad assabbour
Reactive forms
Les formulaires pilotés par le code

267Jaouad assabbour
ReactiveForms
Un formulaire piloté par le code (ou reactive form)
permet une validation plus complexe et
personnalisée des données entrées dans le
formulaire
Ces formulaires fonctionnent principalement avec
deux types de composants :
les FormControls(contrôles) et les
FormGroups(groupes de contrôle)

Les contrôles sont des entités qui possèdent une
valeur et un statut de validité, qui est déterminé par
une fonction de validation optionnelle.
Un contrôle peut être lié à un champ, et à sa création,
il prend trois paramètres, toutes optionnelles.
Le premier paramètre est la valeur par défaut
Le second est un validateur
Le troisième est un validateur asynchrone

Pour utiliser les ReactiveForms, il faut d’abord les
importer dans le module :
import{ReactiveFormsModule}from'@angular/forms';
Si ReactiveFormsModule est importé, il n’est
pas nécessaire d’importer FormsModule,
ReactiveFormsModule importe lui-même
FormsModule.
Jaouad assabbour

this.login=newFormControl('Defaultvalue',Vali
dators.required);
Pour utiliser un contrôle, il faut donc l’instancier
dans un premier temps.
Le second paramètre peut très bien être un tableau
pour permettre de fournir plusieurs validateurs au
FormControl
Jaouad assabbour

Voici la liste des validateurs existants :
Validateur Effet
min Valeur minimale du champ
max Valeur maximale du champ
required Le champ ne doit pas être vide
requiredTrue Requiert une valeur true (pour les checkboxes)
email Le champ doit passer une validation email (_@_._)
minLength Le champ doit avoir un nombre de caractères
minimal
maxLength Le champ doit avoir un nombre de caractères
maximal
pattern Accepte une chaine de caractère ou une regex

login:FormControl;em
ail:FormControl;login
Form:FormGroup;
constructor(privatefb:FormBuilder){
this.login=this.fb.control(''[Validators.required,Validators.minLength(4)]);
this.email=this.fb.control(''[Validators.required,Validators.email]);
this.loginForm=this.fb.group({login:this.login,email:this.email});
}
Angular met à disposition un builder nommé
FormBuilder qui permet de créer des
controls et des groupes.
Jaouad assabbour

Cela change donc la vue HTML en conséquence. Ce n’est plus la directive
[(ngModel)] qui va être utilisée mais [formGroup] et [formControl]
<form [formGroup]="loginForm">
<label for="login">Login</label>
<input type="text" [formControl]="login" />
<button type="submit">Submit</button>
</form>
Jaouad assabbour

Il est aussi possible d’utiliser formControlName au lieu du formControl. Cela
permet d’éviter de stocker forcément tous les contrôles dans des variables, car le
formControlName va permettre de ne renseigner que le nom du contrôle.
<form [formGroup]="loginForm">
<label for="login">Login</label>
<input required type="text" formControlName="login" />
<button type="submit">Submit</button>
</form>
Jaouad assabbour

Cela continue donc de fonctionner, et nous pouvons même retirer la
propriété login de notre composant. Angular va pouvoir faire le lien entre
l’input et le FormControl via le nom login qui est spécifié à la création du
FormGroup.
this.loginForm = this.fb.group({
login: this.login,
email: this.email
});
Jaouad assabbour

En accédant à la propriété errors du FormControl login, ou bien en passant
par la méthode hasError(), il est possible de savoir si tel ou tel validateur
est en erreur. Si c’est le cas, une propriété du nom du validateur
existera sur cet objet errors.
<form [formGroup]="loginForm">
<label for="login">Login</label>
<input required type="text" [formControl]="login" />
<div *ngIf="login.dirty && !login.valid">
<p *ngIf="login.hasError('minlength')">
Le login doit comporter au moins 4 caractères</p>
</div>
<button type="submit">Submit</button>
</form>
Jaouad assabbour

284Jaouad assabbour
HttpClient

285Jaouad assabbour
Http
HttpClientModule utilise les classes du package
@angular/common/http
Ce module Http permet de bouchonner notre serveur
pour les tests, de retourner des réponses données et
utilise la programmation réactive

Le module Http propose un service nommé
HttpClient qu’on peut injecter dans n’importe quel
constructeur. Il ne faut pas oublier d’importer le
module HttpClientModule dans le module racine.
Ensuite on peut injecter le service HttpClient où l’on veut :
Jaouad assabbour

Par défaut, le service HttpClient réalise des requêtes AJAX avec
XMLHttpRequest. Il propose plusieurs méthodes, correspondant
au verbes HTTP communs :
•get
•post
•put
•delete
•patch
•head
•jsonp
En Angular, toutes ces méthodes retournent un objet Observable
Jaouad assabbour

Commençons par récupérer les users enregistrées dans UserService
On supposera qu’un serveur est déjà prêt et disponible, fournissant une API
RESTful.Pour charger les users, on enverra une requête GET sur une URL genre
'https://my/api/users' Cela retourne un Observable. On peut s’y abonner
pourobtenir la réponse. Le corps de la réponse est la partie laplus intéressante, et
est directement émis par l’Observable
Jaouad assabbour

On peut aussi accéder à la réponse HTTP complète.
L’objet retourné est alors une HttpResponse, avec
quelques champs comme le champ status (code de la
réponse), le champ headers, etc.
L’observable échoue si la réponse a un statut
différent de 2xx ou 3xx, et l’erreur récupérée est
alors une HttpErrorResponse
jaouad assabbour

Évidemment, on peut ajuster les requêtes plus finement.
Chaque méthode accepte un objet options en paramètre optionnel,
où l’on peut configurer la requête
L’option params représente les paramètres de recherche (que l’on
appelle aussi query string) à ajouter à l’URL
Jaouad assabbour

L’option headers est pratique pour
ajouter quelques headers custom à la
requête.
Cela est notamment nécessaire pour
certaines techniques
d’authentification, comme par
exemple
JSON Web Token (JWT) :
Jaouad assabbour

298Jaouad assabbour
Module

299Jaouad assabbour
Module
• Avant de nous aventurer plus en profondeur dans
les composants, voyons également ce qu’est un
module
• Un module représente un conteneur regroupant
l’ensemble des éléments de l’application. Comme
pour le composant, nous avons besoin d’un module
racine dans lequel nous allons pouvoir ajouter
notre composant AppComponent. Sans trop de
surprises, le nom de ce module est AppModule.
• Un module est représenté par une classe
TypeScript décorée par NgModule.

300
Contenu de app.module.ts
Jaouad assabbour
•@NgModule :pour déclarerla
classe comme un module
•AppModule :le nom de la classe
•declarations: liste des éléments,
composants et autres, à inclure dans
le module
•imports :liste des modules que
notre module va importer
•providers :services utiles à notre
module
•bootstrap :élément sur lequel
l’application Angular va démarrer
(chargé dans declarations)
@NgModule({
declarations:
[AppComponent],imports:
[BrowserModule],providers:
[],
bootstrap:[AppComponent],
})
exportclassAppModule{}

Ce module :
• Importe le module BrowserModule contenant tous les éléments de
base permettant de construire une application,
• Enregistre le composant créé précédemment et le déclare en tant
que composant sur lequel l’application doit démarrer.
• Ensuite, on peut aussi voir le AppRoutingModule qui est le
module par défaut créé par la CLI (quand on a demandé un module
de routing à la création) qui va
nous permettre de définir les URL de chaque page.
Jaouad assabbour

303Jaouad assabbour
Module
Les applications Angular sont modulaires. Angular a son propre
système de modularité appelé NgModules. Les NgModules sont
des conteneurs pour un bloc de code cohérent dédié à un domaine
d'application, un flux de travail ou un ensemble de capacités
étroitement liées. Ils peuvent contenir des composants, des
fournisseurs de services et d'autres fichiers de code. Ils peuvent
importer des fonctionnalités qui sont exportées à partir d'autres
NgModules et exporter des fonctionnalités sélectionnées pour une
utilisation par d'autres NgModules.

304Jaouad assabbour
Module
Chaque application Angular a au moins une classe
NgModule, le module racine, qui est conventionnellement
nommé AppModule et réside dans un fichier nommé
app.module.ts. Vous lancez votre application en amorçant le
NgModule racine.
Alors qu'une petite application peut n'avoir qu'un seul
NgModule, la plupart des applications ont beaucoup plus de
modules fonctionnels. Le NgModule racine pour une
application est ainsi nommé car il peut inclure les NgModules
enfants dans une hiérarchie de n'importe quelle profondeur.

Importons le module de routes, les 2 composants et
exportons notre tableau de routes

Module
Nous n'avons plus besoin du module de routage dans
notre module racine. Et la constante route étant
exportée, il est possible de l'invoquer dans un menu
Jaouad assabbour 308

311Jaouad assabbour
Lazy Loading

Inévitablement, les applications s’enrichissent de plus en plus
de fonctionnalités, et leur taille ne fait qu’augmenter, jusqu’au
point où ça devient un problème : le fichier JS consomme trop
de bande passante et met trop longtemps à être téléchargé et
analysé, en particulier sur les téléphones mobiles et les réseaux
de mauvaise qualité
Par ailleurs, le nombre de fonctionnalités augmentant,
certaines d’entre elles ne sont utilisées que par certains
utilisateurs, ou par tous, mais rarement
Charger ces fonctionnalités dès le démarrage de l’application
est un gaspillage de bande passante et une perte de temps pour
l’utilisateur
Jaouad assabbour

C’est là que le chargement à la demande (lazy loading) devient
intéressant
Le chargement à la demande consiste à diviser l’application en
plusieurs modules Angular
Un module chargé à la demande définit ses propres routes,
composants et services, tous empaquetés dans un fichier JavaScript
qu’on appelle un bundle, distinct du bundle principal de
l’application
Le module principal de l’application, lui, ne fait que définir une
route permettant d’accéder à ce module chargé à la demande
Jaouad assabbour

La première étape consiste à définir un module Angular pour cette
partie réservée à l’administration
Il y a une importante différence entre ce module fils, et le module racine
de l’application : Ce module fils n’importe pas BrowserModule. À la
place, il importe CommonModule
Jaouad assabbour

La seconde étape consiste à définir un composant admin et à définir nos
routes :
Au lieu d’utiliser RouterModule.forRoot(), il faut utiliser RouterModule.forChild(), parce
que ce module est un module fils, et non le module racine de l’application Comme le routeur
est un singleton et conserve un état (l’ensemble des routes), il ne s’agit pas d’en avoir deux
instances dans l’application C’est la raison pour laquelle forChild() est utilisé
Jaouad assabbour

L’étape finale est d’ajouter une route dans le fichier de configuration des routes du module
racine (app.routes.ts), et d’indiquer au routeur qu’il faut charger le module d’administration
lorsqu’on navigue vers cette route(ou une des routes filles qu’il pourrait avoir) :
Ceci est réalisé grâce à la propriété loadChildren de la route
d’administration
La valeur de cette propriété est une chaîne de caractères,
contenant
le chemin relatif du module d’administration à charger
dynamiquement, suivi de # et du nom de la classe décorée par
NgModule
Lorsque l’application est construite, Angular CLI analyse la
configuration des routes et détecte que le module d’administration
doit être chargé à la demande
Jaouad assabbour

318Jaouad assabbour
Testing

319Jaouad assabbour
Testing
On peut écrire deux types de tests :
•tests unitaires : qui vont tester des éléments
unitairesde code(méthodes)
•tests end-to-end: de bout en bout, qui vont tester toute
notre application
Pour lancer les tests :ng test
Pour stopper les tests : CTRL+C dans la console

320Jaouad assabbour
Tests Unitaires

321Jaouad assabbour
Tests unitaires
Ces tests garantissent seulement qu’une petite partie de
l’application fonctionne comme prévu, mais ils ont de
nombreux avantages :
• ils sont vraiment rapides, on peut en exécuter plusieurs
centaines en quelques secondes
• ils sont très efficaces pour tester (quasiment) l’intégralité du
code, et particulièrement les cas limites, qui peuvent être
difficiles à reproduire manuellement dans l’application réelle

Un des concepts du test unitaire est celui d’isolation
: Cela permet de s’assurer qu’une fonctionnalité
précise, aussi minime soit-elle, est opérationnelle.
Pour tout cela, on va compter sur quelques outils. Un
des framework de test les plus populaires (et
accessoirement utilisé par Angular) est Jasmine. Nos
tests se lanceront dans le task runner Karma
Jaouad assabbour

Par défaut, avec Angular CLI, ce sont tous les fichiers
ayant l’extension .spec.ts et qui correspondent à un
fichier TypeScript, qui vont être exécutés.
L’objectif est que chaque fichier TypeScript possède
un fichier de test, pour avoir une couverture de code
maximum.
Jaouad assabbour

324Jaouad assabbour
Jasmine
Jasmine est un framework de test open source basé sur
le BDD (Behaviour-Driven Development).
L’objectif est de mettre l’accent sur les spécifications,
les tests rédigés étant alors explicites et fortement liés à
ces spécifications. Dans un cadre Agile, les tests
représentent les différentes User Stories définissant les
spécifications de l’application.
Cela apporte un processus d’écriture des tests plus fluide
et plus efficace.

Plusieurs concepts assez communs au BDD sont alors retrouvés
au sein de Jasmine :
• describe : définit le titre du test et donne la fonction
contenant les diverses spécifications.
• it : possède le titre d’une spécification et contient les tests validant cette
spécification. Plus précisément, ce
sont des assertions.
• expect : une assertion entre deux valeurs. Par exemple : la valeur A DOIT
être égale à la valeur B. L’assertion se base sur un matcher.
• Matcher : des helpers mis à disposition pour rédiger les assertions, comme
toEqual ou toContain.
Jaouad assabbour

En prenant un exemple très simple, avec une
fonction d’addition comme celle-ci :
function add(a: number, b: number) {
return a + b;
};
Il serait alors possible d’écrire un test unitaire qui
s’assure que la fonction add renvoie bien l’addition
de deux nombres donnés.
Jaouad assabbour

describe("Tests de méthodes manipulant des
nombres", () => {
it("La méthode devrait additioner les
deux valeurs", () => {
let a = 1;
let b = 2;
let resultFromAdd = add(a, b); 3
expect(resultFromAdd).toEqual(3);
});
}
);
Jaouad assabbour

328Jaouad assabbour
Exécuter du code avant/ après nos tests
Dans une méthode describe contenant plusieurs méthodes it, il est fréquent d’avoir
à initialiser certaines variables. Pour éviter la redondance de code d’initialisation
dans chaque test, il est possible de l’écrire une seule fois grâce à la méthode
beforeEach de Jasmine.
describe(’Exemple initialisation’, () =>
{
let value:string;
beforeEach(() => { value =
"Init"; })
it(’Test 1’,()=>{ /* ... */ });
}

Il existe l’équivalent pour exécuter du code après les tests
grâce à la méthode afterEach, ainsi que les méthodes
beforeAll et afterAll, qui ne s’exécutent qu’une seule fois
avant et après l’exécution de tous
les tests.
Jaouad assabbour

Pour pouvoir exécuter du code relatif à un test après qu’il ait
échoué, il est possible de récupérer l’état d’un test au sein d’une
méthode afterEach. Ainsi avec une condition sur cet état, il suffit
de rajouter le code voulu.
afterEach(()=> {
var passed =
jasmine.getEnv().currentSpec.results().passed();
if (!passed) {
// code à exécuter lorsque le test a échoué
}
});
Jaouad assabbour

331Jaouad assabbour
La syntaxe d’un matcher est relativement simple et vient étendre un
expect. En réalité, ce qui est important, c’est le couple
expect/matcher : expect(valeurA).matcher(valeurB);
L’expect prend en paramètre la valeur à tester (valeurA) et le
matcher prend en paramètre la valeur attendue (valeurB), ce qui
permet d’effectuer l’assertion de validité de la valeur à tester.

332Jaouad assabbour
Matcher Définition
expect(a).toEqual(b) égalité entre deux valeurs (==)
expect(a).toBe(b) égalité stricte (===)
expect(fct).toThrow() la fonction throw une erreur
expect(fct).toThrowError('err') la fonction throw l'erreur 'err'
expect(array).toContain(val) le tableau contient la valeur
expect(string).toContain(substring) la chaine contient la sous-chaine
expect(a).toBeGreaterThan(b) supériorité stricte (>)
expect(a).toBeLessThan(b) supériorité stricte (<)
expect(a).toBeGreaterOrEqualThan (b) supériorité (>=)
expect(a).toBeLessOrEqualThan(b) supériorité (<=)
expect(a).toBeFalsy() /
expect(a).toBeTruthy()
évalué à false / true dans le contexte
booléen
expect(a).toBeFalse() /
expect(a).toBeTrue()
false / true
expect(a).toBeNull() /
expect(a).toBeUndefined()
null / undefined
expect(a).not.toEqual(b) Négation du matche

333Jaouad assabbour

333Jaouad assabbour
Tester un
composant

334Jaouad assabbour
Tests de composants
Avec les nombreux matchers mis à disposition ainsi
que les matchers personnalisés, il est alors possible
de commencer à tester l’application, du moins les
briques de l’application, et donc les composants
Angular.
Un test de composant est légèrement particulier car
il nous faut fournir le composant à Jasmine. Cela se
fait avec un «test bed»
Commençons par écrire un composant à tester.

335
Tester un composant
Jaouad assabbour
Le composant à tester :
@Component({
selector: ’app-mycomponent’,
template: `<div id="contentDiv">{{myContent}}</div>`
})
export class MyComponent{
myContent: string = "Salut!";
}

336
TestBed
Jaouad assabbour
Le TestBed est le point d’entrée des interfaces de
tests d’Angular.
C’est grâce à lui qu’il va être possible de créer des
composants pour que les tests puissent être écrits.
Autre point important, la configuration des tests est
faite grâce à la méthode configureTestingModule
exposée par le TestBed.
Elle prend en paramètre un objet similaire au
décorateur NgModule :

TestBed.configureTestingModule({
declarations: [MyComponent]
}).compileComponents();
Pour créer le composant, il faut appeler la méthode
createComponent du TestBed en spécifiant le type de
composant à créer.
La méthode createComponent renvoie alors un
ComponentFixture (une représentation de notre composant)
du type du composant demandé.
C’est avec ce ComponentFixture qu’il est possible de
récupérer plusieurs données, comme l’instance du
composant ou même l’élément HTML du composant.
Jaouad assabbour

describe(’MycomponentComponent’,()=>{
let myComponent: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let myComponentHtmlElement:HTMLElement;
let myComponentDebugElement : DebugElement;
beforeEach(async(() =>{
TestBed.configureTestingModule({
declarations:[MyComponent]
}).compileComponents();
fixture=TestBed.createComponent(MyComponent);
myComponent=fixture.componentInstance;
myComponentDebugElement=fixture.debugElement;
myComponentHtmlElement =
myComponentDebugElement.nativeElement;
}));
•fixture:instanciat
ion du composant
•componantInst
ance:les
données
relatives à la
classe
•nativeElement
: les données
relatives au hmtl
Jaouad assabbour

339Jaouad assabbour
Vérifier l'instanciation
Il est alors possible d’écrire un premier test validantqu’après la création du
composant, son instance est bien définie, en utilisant la variable initialisée dans le
beforeEach : myComponent. Premier test : l’instance du composant est définie
it(’Le composant doit être instancié’, () => {
expect(myComponent).toBeTruthy();
});

340Jaouad assabbour
Contrôler les propriétés
Sachant qu’il est possible de récupérer l’instance ducomposant, cela veut
dire qu’il est tout à fait possible
d’accéder aux propriétés de ce composant et de tester leurs valeurs.
it(’La propriété myContent doit avoir la
valeur Salut !’, async(() => {
expect(myComponent.myContent)
.toEqual(’Salut !’);
}));

341Jaouad assabbour
S'assurer quele rendu est cohérent
Le composant est censé afficher sa propriété myContent dans une div
portant l’id "contentDiv". Pour vérifier que cela est bien le cas, il faut
inspecter le DOM et le contenu de la div.
Grâce à la propriété fixture.myComponentDebugElement.nativeElement
qui est stockée dans la variable myComponentHtmlElement, il est
possible d’aller rechercher la div en question grâce à la méthode
querySelector.
En récupérant une référence vers la contentDiv, une comparaison entre la
propriété myContent et le contenu de la contentDiv est alors suffisante.

342Jaouad assabbour
S'assurer que le rendu est cohérent
it(’La div #contentDiv doit contenir la valeur de la
propriété myContent du composant’, async(() => {
fixture.detectChanges();
expect(myComponentHtmlElement.querySelector(’#contentDiv
’).textContent)
.toContain(myComponent.myContent);
}));

Avant d’effectuer le test, il faut lancer une détection
de changement avec la méthode detectChanges depuis la fixture.
Cela est dû au fait que la propriété est affichée par binding, il faut alors
dire à Angular de lancer les mécanismes de détection de changement pour
que le détecteur de changement du composant en question réalise que le
DOM doit être mis à jour.
Jaouad assabbour

On remarque que la méthode
fixture.detectChanges() est appelée avant le test
d’égalité. Sans détection de changement forcée, le
composant n’est pas rendu, et le test ne passera pas.
Il est possible d’activer la détection de changement
automatique sur un composant précis avec :
fixture.autoDetectChanges(true);
Jaouad assabbour

Ou bien de manière générale sur tous les composants du tests en
ajoutant le ComponentFixtureAutoDetect dans les providers :
TestBed.configureTestingModule({declarations:
[MyComponent], providers:[{
provide:ComponentFixtureAutoDetect,useValue:true
}]
}).compileComponents();
Jaouad assabbour

346Jaouad assabbour
Tester un s e r v i c e

347Jaouad assabbour
Tester un service
Considérons le service MathService
import { Injectable } from
’@angular/core’;
@Injectable()
export class MathService { count: number =
0; incrementCount(i: number) {
this.count++;
}
}

Tester le service MathService peut s’avérer simple. En réalité, il n’est même
pas nécessaire de créer un module de test avec
TestBed.configureTestingModule dans ce cas car il n’y a pas besoin de
récupérer de fixture ou bien de gérer des dépendances.
Le test peut alors être écrit en utilisant le constructeur du service tout
simplement. Après avoir appelé la méthode incrementCount, le test s’assure
que la propriété count est bien incrémentée.
Il est même possible d’appeler plusieurs fois la méthode expect et de s’assurer
qu’après deux incréments, ou plus encore, la propriété count est toujours mise
à jour.
Jaouad assabbour

import { MathService } from ’./math-service’;
describe(’MyServiceService’, () => {
it(’La méthode incrementCount doit incrémenter la
propriété count’,
() => {
let mathService = new MathService();
mathService.incrementCount();
expect(mathService.count).toEqual(1);
mathService.incrementCount();
expect(mathService.count).toEqual(2);
});
});
Jaouad assabbour

Dans une application Angular, les services sont voués
à être injectés. Pour vérifier cela, la première étape
consiste en la création du module de test, puis d’y
ajouter le service dans ses providers.
Ensuite, pour utiliser le service injecté dans les tests,
le deuxième paramètre de it doit être englobé dans
la méthode inject, qui vient elle aussi de
@angular/core/testing, et qui met donc à disposition
l’instance de MathService injectée.
Jaouad assabbour

import { inject, TestBed } from ’@angular/core/testing’;
import { MathService } from ’./math-service’;
describe(’MyServiceService’, () => {
// Ajout du MathService dans les providers
beforeEach(() => {
TestBed.configureTestingModule({
providers: [MathService]
});
});
it(’Le service est bien injecté’, inject([MathService],
(mathService: MathService) => {
expect(mathService).toBeTruthy();
}));
});
Jaouad assabbour

352Jaouad assabbour
Injecter un faux
service

353Jaouad assabbour
Injecterunfauxservice
Avec les tests unitaires, il arrive souvent qu’une brique qui
doit être testée possède des dépendances, comme des
services.
Par exemple, un composant peut utiliser le service suivant :
export class TestService {
public angular: string = "Angular";
doSomething(): number {
return api.doSomething();
}
}

Ce service possède une propriété et une méthode.
Cette méthode fait un appel d’API. Or, dans le test
unitaire du composant, il n’est pas désiré de faire
appel à l’API. C’est pour cela qu’il est possible de «
bouchonner » les services au sein d’un module de
test, comme pour les modules normaux.
Jaouad assabbour

Cela se fait en fournissant aux providers du
TestingModule, un mock qui va venir s’injecter à la
place du vrai service, grâce à la syntaxe suivante :
{
provide: TestService,
useValue: mockTestService
}
Jaouad assabbour

import { TestBed, inject } from ’@angular/core/testing’;
import { TestService } from ’./test.service’;
describe(’TestService’, () => {
let testService: TestService;
beforeEach(() => {
let mockTestService = {
angular: ’Angular’,
doSomething: () => { return 5; }
};
TestBed.configureTestingModule({
providers: [{provide: TestService, useValue: mockTestService}]
});
testService = TestBed.get(TestService);
});
it("test d’un composant...",()=>{
// testService.doSomething() renvoie maintenant 5 au lieu de faire un
appel d’API
}
});
Jaouad assabbour

Le test doit injecter un faux service pour simuler les retours du service TestService.
Pour cela, dans chaque beforeEach, un service est créé à la volée et possède la
même structure de propriétés et de méthodes que le vrai service TestService.
Or, au moment de configurer le module de test et ses providers, il est spécifié que
pour le service TestService, c’est le service mocké qui va être utilisé.
Le TestService injecté est alors récupéré depuis le root injector à l’aide de
Test.get(TestService). Ensuite, dans les tests, lorsque le service est utilisé, c’est bien
le service falsifié qui est utilisé, et non l’implémentation originale du
TestService.
Jaouad assabbour

358Jaouad assabbour
Tests E n d – t o – En d

359Jaouad assabbour
Tests e 2 e
Les tests end-to-end ("de bout en bout", abrégés en e2e) sont l’autre type
de tests qu’on peut faire.
Un test end-to-end consiste à lancer réellement l’application dans un
navigateur et à simuler
l’interaction d’un utilisateur (clic sur les boutons, saisie de formulaires,
etc.).
Ils ont l’avantage de vraiment tester l’application dans son ensemble,
mais :
• ils sont bien plus lents (plusieurs secondes par test)
• c’est souvent difficile de tester les cas limites

On ne choisit pas entre les tests unitaires et les tests
e2e : on combine les deux pour avoir à la fois une bonne couverture
et quelques garanties que l’application complète fonctionne comme
prévue
Les tests e2e s’appuient sur un outil appelé Protractor
On écrira une suite de tests avec Jasmine comme pour un test
unitaire, mais on utilisera l’API de Protractor pour interagir avec
l'application
Les tests e2e se trouvent dans le répertoire e2e/src
d'Angular
Jaouad assabbour

Un test simple ressemblerait à :

Protractor nous fournit un objet browser, avec quelques
méthodes utilitaires
• get() pour aller à une URL.
• element.all() pour sélectionner tous les éléments répondant à un
prédicat donné.
• by : Le prédicat element.all() s’appuie souvent sur by et ses méthodes
variées : by.css() pour faire une requête CSS, by.id() pour récupérer un
élément par son identifiant, etc.
• count() : element.all() retournera une promesse, avec une méthode
spéciale count() utilisée dans le test ci-
dessus.
Jaouad assabbour

Protractor nous fournit un objet browser, avec quelques
méthodes utilitaires
• $('h1') est un raccourci, équivalent de element(by.css('h1')). Il récupérera
le premier élément correspondant à la requête CSS.
On peut utiliser plusieurs méthodes sur la promesse retournée par $()
• getText() pour récupérer le texte content
• getAttribute() pour récupérer les attributs
• click() pour simuler un clic
• sendK
Jaouad assabbour

• Ces tests peuvent être bien plus longs à écrire et à
débugger (bien plus que des tests unitaires), mais ils
sont vraiment utiles.
• On peut faire plein de trucs incroyables avec ces tests,
comme tester dans plusieurs navigateurs, prendre une
capture d’écran à chaque échec, etc.
• Avec les tests unitaires et les tests e2e, on a toutes les
cartes en main pour construire une application solide et
maintenable.
• La doculentation complète de protractor est
disponnible ici https://www.protractortest.org/#/api
Fin ...