Bienvenue sur CodeWise ! Si vous êtes nouveau ici, vous voudrez sans doute découvrir notre Starter Kit Angular : il contient une roadmap du parcours d'un dev Angular, ainsi qu'un cookbook des commandes les plus utiles et un extrait de formation. Cliquez ici pour le télécharger (c’est gratuit !)
Un composant Angular, à quoi ça sert ? Et comment les utiliser correctement ?
Un composant c'est quoi ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Component({
selector: 'app-todo',
templateUrl: './todo.component.html', // or template: '<p>todo works!</p>',
styleUrls: ['./todo.component.css'], // or styles: ['p { color: red }'],
animations: [],
encapsulation: ViewEncapsulation.Emulated,
exportAs: 'todo'
})
export class TodoComponent {
@Input()
options: any;
@Output()
notify: EventEmitter<string> = new EventEmitter<string>();
todos: string[];
constructor() { }
addTodo(message: string) {
this.todos.push(message);
}
}
En terme de concept
Un composant (component) est une unité de découpage visuel.
Les pages sont des composants, elles-mêmes découpées en plusieurs composants. L'idée est de séparer les pages web en composants pour ne pas se contenter de découper par langage (les fameux dossiers js, html, css ou autre).
On donne ainsi une structure logique au projet et à nos fichiers.
En terme de code
Un composant, c'est une classe Typescript avec des attributs, méthodes et constructeur et qui sert d'unité de découpage visuel dans un projet front. Il possède aussi des métadonnées qu'on lui injecte via la directive @Component.
On définit un composant dans Angular par un ensemble de ressources :
- une portion de HTML
- une ou des feuilles de styles associée(s) à ce HTML
- une classe TypeScript ou JavaScript
Pour l'instancier, on utilise son sélecteur qui correspond à un tag HTML. Vous pouvez donc intégrer votre composant directement dans un bloc HTML, en utilisant son tag HTML associé.
Un composant est réutilisable autant de fois que nécessaire. Par conséquent, on ne code un composant qu'une fois pour plusieurs affichages.
On a également accès à son cycle de vie, via des hooks et il peut posséder n entrée/sortie pour communiquer avec d'autres composants.
Communication entre composants
Les méthodes dites view et content sont 2 approches différentes pour faire communiquer des composants.
La principale différence se trouve dans le partage du scope (la portée des variables) entre les composants parent et enfant.
La méthode view
- Scope isolé entre les composants
- Couplage composant parent/enfant lourd
Chaque composant gardant son scope isolé de l'autre, les directives @Inputs et @Outputs leur permettent de s’échanger des valeurs.
@Input
Input, permet de spécifier une valeur en entrée du composant. Pour l'utiliser, vous allez devoir modifier le code à 2 endroits :
- Déclarez-le avec l'annotation @Input() dans le composant (fichier ts)
- Liez-le en “one-way” binding avec [myInputVarNameHere] dans le template html du parent
1
2
3
4
5
6
7
8
@Component({
selector: 'app-todo',
})
export class TodoComponent {
@Input()
todo: any;
...
}
1
<app-todo [todo]="todo"></app-todo>
@Output
@Output, permet de spécifier un événement en sortie du composant. Pour l'utiliser, vous devez modifier le code à 3 endroits :
- Instanciez un attribut de type EventEmitter dans le composant (ts) qu'on décore avec la directive @Output
- Liez-le en event-binding avec (myOutputVariableName) dans le template HTML du parent
- Faîtes appel à la fonction emit() de l'EventEmitter au moment ou l'output doit se produire
1
2
3
4
5
6
7
8
@Component({
selector: 'app-todo'
})
export class TodoComponent {
@Output()
notify: EventEmitter<any> = new EventEmitter();
...
}
1
<app-todo (notify)="displayChecked($event)"></app-todo>
La méthode content
- pas d’input/output
- scope partagé entre les composants
- plus souple, plus facilement réutilisable
La balise ng-content
Pour mettre en place la projection de contenu de la méthode content, vous allez devoir modifier le code à 2 endroits :
- Ajoutez du HTML à l'intérieur des balises de l'enfant, dans le fichier HTML du parent
- Récupérez-le dans le composant enfant, en projetant son contenu dans une balise <ng-content>
1
2
3
4
5
6
7
8
9
@Component({
selector: 'fa-input',
template: `
<i class="fa" [ngClass]="classes"></i>
<ng-content></ng-content>
`
})
export class FaInputComponent {
}
1
2
3
4
<h1>FA Input</h1>
<fa-input>
<input type=”email” placeholder=”Email”/>
</fa-input>
Vous remarquez que, dans le composant parent, on a placé du contenu html à l'intérieur de notre balise de composant <fa-input>
Ce contenu est rendu disponible dans le composant fils via la balise <ng-content>. On dit que le contenu de la balise <fa-input> (parent) est projeté dans la balise <ng-content>
Vous connaissez maintenant les principes de la méthode view et de la projection de contenu !
Dans quel cas l'utiliser ?
La plupart du temps, on utilise la méthode view avec des Input/Output pour structurer la circulation des données au sein d'une page. Cela s'explique car le couplage entre les composants est fort, il s'agit d'un découpage spécifique à la page. De plus on souhaite isoler les scopes au possible.
Mais dans certains cas, il n'est vraiment pas pratique de garder des scopes isolés, et donc d'utiliser la méthode view.
Par exemple, si vous comptez réutiliser un composant souvent et que vous devez accéder à 5 de ses attributs, vous allez devoir gérer beaucoup d'Input/Output. C'est souvent le cas quand vous voulez séparer des formulaires sur plusieurs composants, ou rendre un formulaire générique.
Pour ces cas-là, vous pouvez choisir la méthode content.
Vous aurez donc un couplage plus faible mais une séparation néante des scopes entre les composants (le scope de l'enfant n'existe pas, celui du parent contient tout).
Si vous souhaitez bien comprendre les différents cas d'utilisation, je vous recommande ce tutoriel d'Angular University : Tutoriel pour maitriser la différence view/content
Passons maintenant au cycle de vie des composants !
Cycle de vie d'un composant
Angular vous permet d'exécuter du Javascript lors de certains évènements liés au cycle de vie du component.
Cela peut s'avérer utile, par exemple pour lancer un appel API au chargement d'une page ou bien pour supprimer une ressource lors de la destruction de l'instance du composant.
ngOnChange
- ne s’exécute pas si pas d’@Input
- 1er hook appelé après l’appel au constructeur
- déclenché à chaque changement de donnée en entrée @Input()
ngOnInit
- intervient après l’appel de ngOnChange()
- déclenché après l’initialisation du composant
- appelé uniquement une fois
ngDoCheck
- intervient après l’appel de ngOnInit()
- ne s’exécute pas si ngOnChange est implémentée
ngAfterContentInit
- s'exécute lorsqu’un content (ng-content) est initialisé
- @ContentChildren et @ContentChild sont valorisées
ngAfterContentChecked
- exécuté à chaque détection de changement
- @ContentChildren et @ContentChild sont valorisées
ngAfterViewInit
- exécuté une fois les vues enfants initialisé
ngAfterViewChecked
- exécuté à chaque détection de changement
- @ViewChildren et @ViewChild sont valorisées
ngOnDestroy
- exécuté avant la suppression du composant
Sources
- Guide officiel d'Angular sur les composants : Angular - Introduction to components and templates
- Les Input/Output : @Input() and @Output() properties
- Bien utiliser la méthode content : How To Use ng-content To Improve Component API Design
- Cycle de vie des composants : Angular - Hooking into the component lifecycle
Téléchargez votre Starter Kit Angular
En souscrivant vous recevrez :
- Une roadmap d'un développeur Angular
- Un cookbook Angular des commandes les plus utiles
- Un extrait de formation
100% gratuit.