Les composants
Introduction
Ce chapitre présente la pierre angulaire d’Angular, les composants. L’objectif est dans un premier temps de savoir ce qu’est un composant et quels sont les parties qui le structurent. Dans un second temps, il est primordial d’aborder les différents types de paramètres que peut avoir un composant : les inputs et outputs. Ensuite, dans une application, plusieurs composants cohabitent et doivent interagir entre eux, cela mène à des interactions entre composants, concept qui peut être représenté sous la forme de plusieurs mécanismes. Enfin, des notions plus spécifiques à Angular comme la View Encapsulation et la détection des changements sont abordées.
Qu’est-ce qu’un composant ?
1. Une première définition
Le composant est la structure fondamentale d’une application Angular. Comme on peut le retrouver dans d’autres frameworks, ou avec les Web Components tout simplement, l’application est découpée en composants, pouvant contenir eux-mêmes d’autres composants.
Les objectifs principaux, qui sont aussi des atouts, sont la réutilisation ainsi qu’un découpage logique. Supposons qu’une application est censée gérer une liste d’une entité spécifique. Il y aura alors de nombreux éléments à afficher, par le biais d’une liste par exemple. Nous allons donc créer un composant affichant un seul et unique élément, et boucler autour de celui-ci pour afficher tous les éléments.
Par exemple, dans une page contenant un en-tête et listant des articles, deux composants peuvent être déjà identifiés : l’article et l’en-tête.
L’idée est donc de créer ces deux composants une seule fois, et de les réutiliser lorsqu’il est nécessaire de les intégrer.
La structure d’un composant est découpée en plusieurs parties. Tout d’abord, il y a la déclaration de celui-ci, puis, dans cette déclaration, le template du composant et son style.
Ensuite viennent les outillages fournis par Angular, comme les événements du DOM, la gestion des animations ou des notions spécifiques à Angular.
Un composant va appartenir à un module. C’est donc sur le module approprié que l’on va déclarer le composant.
En ce qui concerne le nommage, les développeurs d’Angular préconisent de suffixer le nom par component, on se retrouve ainsi avec des noms de composants de...
Les inputs et outputs
1. Les inputs d’un composant
a. Déclarer une variable en tant qu’Input
Pour qu’une application basée sur les composants puisse fonctionner, il est essentiel de pouvoir rendre les composants paramétrables. Pour cela, Angular fournit le décorateur @Input, celui-ci va permettre d’identifier une propriété du composant en tant qu’input dudit composant. L’input peut être de n’importe quel type TypeScript, un number, un string, ou même une classe/interface que vous aurez créée.
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html',
styleUrls: ['./todo.component.css']
})
export class TodoComponent {
@Input()
text: string;
@Input()
isChecked: boolean;
}
On importe le décorateur @Input depuis @angular/core, et on l’utilise sur les propriétés text et isChecked.
Ces deux propriétés sont donc des inputs du composant Todo et il est maintenant possible de les initialiser dans la balise app-todo.
Propriétés renseignées en dur
<app-todo text="Faire les courses" isChecked="true">
</app-todo>
Dans le premier exemple, ce sont des propriétés "en dur" qui ont été spécifiées. Or il est possible de passer des propriétés du composant parent. Par exemple, avec deux propriétés dans le composant parent, qui affiche le composant Todo :
Propriétés du composant parent
todoChecked: boolean = true;
todoName: string...
Interaction entre composants
Les interactions entre composants sont un sujet très important car les composants sont au cœur des applications Angular. Sans communication entre composants, les développements seraient quasiment impossibles. Heureusement, Angular offre de nombreuses possibilités pour faire communiquer plusieurs composants entre eux, que ce soit du parent vers l’enfant, de l’enfant vers le parent, ou entre plusieurs composants qui n’ont pas forcément de lien de parenté direct.
1. Passer une donnée du parent vers l’enfant à l’aide d’un input
Cette méthode est l’utilisation simple d’un Input. Le composant parent possède une propriété qu’il va transmettre au composant enfant à l’aide d’un input de ce composant enfant.
Composant parent
@Component({
selector: 'app-parent',
template: `<div>
Le parent possède :
<pre>{{ data | json }}</pre>
<hr />
<!-- Les propriétés du parent sont passées au composant enfant -->
<app-children [name]="name" [email]="email"></app-children>
</div>`,
styles:[`
:host{
display:inline-block;
}
hr{
width:100px;
}`]
})
export class ParentComponent {
name: string = "Parent"; ...
Les décorateurs @ViewChild et @ViewChildren
Lorsqu’il est nécessaire de manipuler un ou plusieurs composants enfants, d’accéder à ses données, de les modifier ou bien d’appeler ses méthodes, il est intéressant de faire appel aux décorateurs @ViewChild et @ViewChildren. Ces décorateurs permettent de faire une « view query », ainsi le détecteur de changement va chercher le premier élément qui correspond dans le DOM.
1. Récupérer une référence avec @ViewChild
Le décorateur @ViewChild permet de référencer une instance d’un composant en déclarant une propriété du type du composant enfant, puis en la décorant du décorateur @ViewChild. Le décorateur prend en paramètre un type ou bien une chaîne de caractères.
En spécifiant un type, il est possible de déclarer le type de composant que nous souhaitons référencer :
@ViewChild(ChildComponent)
childrenComponent: ChildComponent;
En spécifiant une chaîne de caractères, nous allons récupérer le composant (ou l’élément, la directive…) qui est référencé en tant que variable locale avec la clé correspondante. Nous avons alors au niveau du TypeScript :
@ViewChild('refChildren')
childComponent: ChildComponent;
Puis, du côté du template HTML :
<app-children #refChildren></app-children>
Tout comme les variables locales, les décorateurs @ViewChild et @ViewChildren ne s’arrêtent pas aux composants, ils permettent aussi de récupérer des références d’élément (ElementRef) pour accéder à leurs propriétés.
Nous allons alors pouvoir appeler...
Les composants Angular et la View Encapsulation
1. Le Shadow DOM
Pour pouvoir appréhender le concept de View Encapsulation (encapsulation des vues), il est important de comprendre ce qu’est le Shadow DOM. Le Shadow DOM est une notion venant des standards des Web Components, qui permettent d’encapsuler des parties du DOM, ainsi que des styles.
Cela veut dire qu’il est possible de limiter le champ d’action d’un script ou d’un style à un élément précis. Il est alors possible d’appliquer des styles bien précis à un seul nœud du DOM, sans que tout le reste de l’application soit impacté.
Il est assez évident que cette notion est primordiale pour une application qui se construit autour de composant. Chaque composant a besoin de son style particulier, or il serait embêtant que le style défini pour un composant soit appliqué à tout le reste de l’application.
Concrètement, avec Angular, en prenant l’exemple ci-dessous d’un template de composant ainsi que du style de celui-ci, il va être possible d’utiliser de simple sélecteur, comme en-tête ou même p.paragraph. Le style est appliqué uniquement au composant en question grâce au concept du Shadow DOM. Cela devient très pratique, voire essentiel, lorsqu’on souhaite utiliser des composants tiers, qui ont besoin de leur propre style.
Template d’un composant
<header>
Header
</header>
<section>
<h1 class="title">Titre</h1>
<p class="paragraph">Texte du paragraphe...</p>
</section>
Exemple de style
<style>
header {
font-size: 2em;
background: red;
...