Faire communiquer les composants en Angular
Le concept principal d’Angular est d’être une SPA, Single Page Application, c’est à dire une application ne possédant qu’une seule page dans laquelle tout est déjà présent.
Pour fonctionner ainsi, le framework repose sur le concept de composants que j’ai abordé dans mon article permettant de créer sa première application avec le cadriciel et que tu peux retrouver et lire dès maintenant.
N.B: Si tu souhaites en apprendre encore plus que dans cet article et si tu souhaites te former correctement sur le long terme, je t’invite à rejoindre ma formation qui te permettra de devenir un véritable junior avec des compétences solides, la formation est disponible et nous t’attendons dès maintenant.
Par défaut, chaque projet possèdera toujours un composant de base, que l’on appelle le composant parent (ou aussi root en anglais). Il portera toujours le nom de AppComponent.
Créer son premier composant
Afin de travailler convenablement, il sera nécessaire de créer une multitude de composants au sein de son application.
La commande à retenir est assez simple et s’exécute à partir du dossier du projet dans un terminal:
ng generate component nom-du-composant
Un composant comportera toujours au moins 4 fichiers:
- la vue (la partie HTML)
- le contrôleur (la partie Typescript)
- le style (la partie CSS/SCSS)
- les tests (la partie qui permet de faire du test unitaire)
Lorsqu’on exécutera la commande, celle-ci effectuera 5 actions au sein du projet Angular.
Les 4 premières actions représenteront la création des 4 fichiers montrés au-dessus. La dernière action permettra de répertorier ce nouveau composant au sein de l’application afin qu’il soit reconnu et utilisable (cela se fait dans le fichier app.module.ts)
Architecture d’un composant
Le cœur d’un composant va être la partie contrôleur, c’est à dire la partie Typescript.
C’est dans cette partie-là que l’on va retrouver toute l’algo et donc toute l’intelligence de notre composant (sil il doit en avoir !)
Faisons un tour du propriétaire ! L’architecture d’un composant sera toujours la même, c’est à dire en 3 parties:
- la première sera les imports nécessaires en haut du fichier
- la seconde sera la partie dédiée au décorateur de classe (fonctionnalité Typescript)
- la dernière sera la classe en elle-même (la partie où l’on mettra toute l’intelligence)
Utilisation d’un composant
Avant d’utiliser un composant, il est nécessaire d’en générer un.
Celui-ci va nous servir pour le reste de l’article.
On lance la commande:
ng generate component who-am-i
On va ensuite modifier la vue de notre composant, on ouvre le fichier who-am-i.component.html et on remplace le contenu par ceci:
<div>Hey, mon nom est Thomas CHEVALIER</div>
Il est maintenant temps d’afficher notre composant. Pour cela, on se rend dans la vue de notre composant principal app.component.html et on va directement remplacer l’intégralité du contenu du fichier par celui-ci:
<app-who-am-i></app-who-am-i>
La balise app-who-am-i permet à Angular de faire la liaison avec l’HTML et le TS de notre composant.
Il ne faut pas oublier de lancer le serveur et de vérifier que tout fonctionne correctement. (on lance la commande « ng serve » dans le dossier du projet)
Interagir correctement avec le DOM
Lorsque l’on débute on a très souvent de bonnes bases Javascript et l’habitude de manipuler le DOM d’une certaine manière.
Que ce soit avec JQuery ou sans ce dernier, il est nécessaire de récupérer l’élément sur lequel on veut travailler puis d’effectuer les modifications dessus.
Avec Angular, tout est beaucoup plus simple.
En réalité, le contrôleur (partie TS) et la vue (partie HTML) d’un composant sont en perpétuel communication. C’est ce qu’on appelle le databinding.
Liaison de données ou databinding
Les composants communiquent de manière instantanée en leur sein.
Chaque composant a une connexion qui est établie entre sa partie Typescript et sa partie HTML.
Cela permet de faire transiter les informations dans un sens (TS vers HTML) comme dans l’autre (HTML vers TS)
Ce système s’appelle le databinding ou liaison de données.
Cette liaison est possible dans deux directions différentes (mentionnées au-dessus):
- du contrôleur vers la vue (on utilisera des outils comme le property binding et la string interpolation)
- de la vue vers le contrôleur (on utilisera l’event binding)
La string interpolation
La string interpolation ou interprétation de valeur est la première chose à connaitre pour afficher du contenu dynamique dans le HTML.
Son rôle est de prendre une variable existante dans la partie contrôleur (TS) d’un composant et d’afficher son contenu dans la partie vue (HTML) de ce même composant.
Nous avons un composant who-am-i qui affiche de manière statique notre nom et notre prénom.
Nous allons faire en sorte que cette donnée soit stockée dans le TS et l’afficher grâce à la string interpolation. Sa notation côté HTML est {{ nomVariable }}.
On remplace le contenu du fichier who-am-i.component.html:
<div>Hey, mon nom est {{firstName}} {{lastName}}</div>
Et on met à jour le contenu du fichier who-am-i.component.ts:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-who-am-i', templateUrl: './who-am-i.component.html', styleUrls: ['./who-am-i.component.css'] }) export class WhoAmIComponent implements OnInit { firstName: string; lastName: string; constructor() { this.firstName = 'Thomas'; this.lastName = 'CHEVALIER'; } ngOnInit(): void { } }
Le property binding
Le property binding ou la liaison de données sur une propriété est un concept qui va nous permettre de lier une propriété d’une balise HTML5 à une variable de notre contrôleur.
Par exemple, un bouton HTML5 peut avoir la propriété disabled ou encore hidden. Si elles sont présentes sur la balise, respectivement, elles désactiveront ou cacheront le bouton. Si elles ne sont pas présentes, il ne se passera rien.
En Javascript Vanilla, nous pourrions ajouter à la volée cette propriété, avec Angular, nous allons pouvoir la lié à un booléen disponible dans le contrôleur.
Sa notation côté HTML est [propriété]= »variableContrôleur ».
On met à jour le contenu du fichier who-am-i.component.html:
<div>Hey, mon nom est {{firstName}} {{lastName}}</div> <button [hidden]="isAgeHidden">Afficher mon âge !</button>
Et on met à jour le contenu du fichier who-am-i.component.ts:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-who-am-i', templateUrl: './who-am-i.component.html', styleUrls: ['./who-am-i.component.css'] }) export class WhoAmIComponent implements OnInit { firstName: string; lastName: string; isAgeHidden: boolean; constructor() { this.firstName = 'Thomas'; this.lastName = 'CHEVALIER'; // Si on change à 'false', le bouton apparaitra this.isAgeHidden = true; } ngOnInit(): void { } }
L’event binding
L’event binding ou la liaison de données sur un évènement permet de se rapprocher de l’utilisation d’un addEventListener en Javascript Vanilla.
La différence réside encore une fois dans le fait que la vue et le contrôleur vont discuter en temps réel et que l’on va pouvoir lier un évènement côté vue à une fonction côté contrôleur.
Les événements sont identiques à ceux qui existent en Javascript Vanilla, comme le click, le mousemove, le mouseup, le mousedown, le input, le submit, le keypress, le keyup, le keydown, etc.
Sa notation côté HTML est (événement)= »fonctionContrôleur ».
Exemple avec notre composant !
On met à jour le contenu du fichier who-am-i.component.html:
<div>Hey, mon nom est {{firstName}} {{lastName}}</div> <button (click)="onClickShowAge()" [hidden]="isAgeHidden">Afficher mon âge !</button>
Et on met à jour le contenu du fichier who-am-i.component.ts:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-who-am-i', templateUrl: './who-am-i.component.html', styleUrls: ['./who-am-i.component.css'] }) export class WhoAmIComponent implements OnInit { firstName: string; lastName: string; isAgeHidden: boolean; constructor() { this.firstName = 'Thomas'; this.lastName = 'CHEVALIER'; // Si on change à 'false', le bouton apparaitra this.isAgeHidden = true; } ngOnInit(): void { } /** * Method called when the user click on the button */ onClickShowAge() { alert('J\'ai 45ans'); } }
Attention, il faut bien penser à changer la valeur de notre variable isAgeHidden pour que le bouton apparaisse !
Propriétés personnalisées
Nous avons vu qu’un composant pouvait communiquer en son sein de 2 manières:
- de la vue vers le contrôleur
- du contrôleur vers la vue
Un composant étant fait pour être réutilisable, il va rapidement être nécessaire d’être capable de savoir le rendre générique.
Pour cela, il va falloir pouvoir le modifier en lui donnant des valeurs en entrée ou bien que lui-même puisse faire passer des informations en sortie. C’est ce qu’on appelle des propriétés personnalisées.
Elles vont permettre au composant « parent », c’est à dire le composant qui invoque le fameux composant réutilisable, de lui faire passer des informations ou d’en réceptionner de la part de ce fameux composant.
On reconnait 2 propriétés:
- l’input ⇒ permet de faire passer une info du parent vers l’enfant
- l’output ⇒ permet de faire remonter une info de l’enfant vers le parent (sous forme d’événement)
L’input est la propriété la plus simple à prendre en main.
On peut la comparer aux paramètres d’une fonction ou encore aux attributs d’une classe.
Notre composant va donc avoir des inputs (on peut dire que c’est des paramètres) qui vont permettre de le construire avec des valeurs différentes.
Reprenons l’exemple de notre composant who-am-i. Si on essaye de l’ajouter plusieurs fois dans notre app.component.html, nous aurons plusieurs fois notre nom qui apparait car le nom est écrit dans notre composant.
Testons et modifions le fichier app.component.html comme ceci:
<app-who-am-i></app-who-am-i> <app-who-am-i></app-who-am-i> <app-who-am-i></app-who-am-i>
Le résultat est le suivant:
Maintenant, nous allons travailler avec des inputs pour faire en sorte que chacune des balises prennent en paramètre le nom et le prénom à afficher.
Il faut commencer par modifier l’enfant, fichier who-am-i.component.ts:
import {Component, Input, OnInit} from '@angular/core'; @Component({ selector: 'app-who-am-i', templateUrl: './who-am-i.component.html', styleUrls: ['./who-am-i.component.css'] }) export class WhoAmIComponent implements OnInit { @Input() firstName: string; @Input() lastName: string; isAgeHidden: boolean; constructor() { this.firstName = ''; this.lastName = ''; this.isAgeHidden = true; } ngOnInit(): void { } /** * Method called when the user click on the button */ onClickShowAge() { alert('J\'ai 45ans'); } }
Ensuite, il faut modifie le parent pour faire passer les informations, fichier app.component.ts:
<router-outlet></router-outlet> <app-who-am-i firstName="Thomas" lastName="CHEVALIER"> </app-who-am-i> <app-who-am-i firstName="Pierre" lastName="DUPONT"> </app-who-am-i>
Résultat à l’affichage:
N.B: Il est possible d’utiliser le property binding sur les inputs dans notre balise de composant !
L’output est beaucoup plus complexe à prendre en main et s’utilise dans des cas très précis. Si tu veux te former sur son utilisation, je t’invite à rejoindre ma formation qui te permettra d’aborder cette notion importante ainsi que de nombreuses autres notions. Nous t’attendons dès maintenant !
Conclusion
Apprendre à développer avec le framework Angular demande du temps et de la pratique. Nous avons vu dans cet article les principaux moyens utilisés pour communiquer au sein d’un composant ainsi qu’à travers une arborescence de composants.
J’aborderais dans un prochain article les notions permettant d’ajouter des conditions de rendu dans la partie HTML créant ainsi des templates personnalisables et puissants.
-
Angular39,00€ TTC