Les Directives Angular permettent d'ajouter du comportement à des éléments HTML. En réalité, tous les components sont des Directives qui ont la spécificité d'avoir aussi un template associé !
Vous utilisez souvent les Directives fournies par Angular :
les structurelles, comme *ngIf ou *ngFor ;
les attributs, comme [ngClass] , [ngStyle] , ou même [formGroup] et formControlName .
Toutes ces Directives viennent ajouter des comportements spécifiques aux éléments sur lesquels elles sont placées. C'est comme si on créait des mini-components autour de ces éléments, l'avantage étant que la même Directive peut être placée sur plusieurs types d'éléments, et à plusieurs endroits de l'application.
Dès que vous avez un comportement que vous souhaitez pouvoir ajouter facilement à plusieurs éléments, la Directive s'annonce généralement comme étant la meilleure approche.
Dans ce chapitre, vous allez créer une Directive simple qui surligne le texte sur lequel elle est placée. Vous y apporterez ensuite quelques améliorations pour qu'elle réagisse aux passages de la souris.
La Directive pourra être utilisée dans toute l'application, donc elle a tout intérêt à être dans SharedModule. Dans le dossier shared , créez un dossier directives et un fichier highlight.directive.ts :
import { AfterViewInit, Directive, ElementRef, Renderer2 } from '@angular/core';
@Directive({
selector: '[highlight]'
})
export class HighlightDirective implements AfterViewInit {
constructor(private el: ElementRef,
private renderer: Renderer2) {}
ngAfterViewInit() {
this.setBackgroundColor('yellow');
}
setBackgroundColor(color: string) {
this.renderer.setStyle(this.el.nativeElement, 'background-color', color);
}
}Il y a plusieurs nouvelles choses ici :
d'abord, le décorateur @Directive , à qui on passe un objet de configuration avec un selector , un peu comme pour les components. Pour pouvoir placer cette directive en tant qu'attribut HTML, le selector doit être entre crochets [] ;
la Directive implémente le lifecycle hook AfterViewInit , car vous devez vous assurer que la view existe avant de commencer à manipuler des éléments qui s'y trouvent ;
dans le constructor , vous injectez ElementRef et Renderer2 :
ElementRef est la référence à l'élément du DOM, et l'injection d'Angular vous permet de l'injecter directement comme ça,
Renderer2 est un outil qui vous permet d'interagir avec le DOM de manière testable, c'est-à-dire que vous pourrez écrire des tests unitaires – qui peuvent être exécutés dans un contexte où le DOM n'existe pas – qui fonctionneront correctement ;
après l'initialisation de la view, vous utilisez la méthode setStyle de Renderer2 pour changer la couleur de fond de l'élément sur lequel la Directive se trouve – l'objet ElementRef le met à disposition via son objet nativeElement .
Il suffit maintenant de déclarer et d'exporter la Directive dans SharedModule, et vous pourrez ensuite l'appliquer sur les éléments de votre application. J'ai choisi de l'appliquer sur les titres des Posts.
Dans post-list-item.component.html :
<span highlight>{{ post.title | titlecase }}</span>C'est aussi simple que ça d'attribuer une Directive ! Dans l'application, ça donne :

Vous pouvez bien sûr appliquer cette Directive à n'importe quel élément HTML, et transformer sa couleur de fond en jaune !
Mais comment pourrait-on aller plus loin ?
Pour permettre aux développeurs qui utilisent votre Directive de choisir la couleur qui est utilisée, vous pouvez y ajouter un @Input , comme pour un component :
import { AfterViewInit, Directive, ElementRef, Input, Renderer2 } from '@angular/core';
@Directive({
selector: '[highlight]'
})
export class HighlightDirective implements AfterViewInit {
@Input() color = 'yellow';
constructor(private el: ElementRef,
private renderer: Renderer2) {}
ngAfterViewInit() {
this.setBackgroundColor(this.color);
}
setBackgroundColor(color: string) {
this.renderer.setStyle(this.el.nativeElement, 'background-color', color);
}
}Vous attribuez une valeur par défaut pour pouvoir utiliser highlight tout seul, mais ici vous permettez également ce genre de syntaxe :
<span highlight color="orange">{{ post.title | titlecase }}</span>Ce qui donne :

Sachez qu'il est également possible de donner le même nom à votre @Input que le selector de la Directive ; par exemple :
@Input() highlight!: string;Ce qui donne, côté template, une syntaxe très lisible :
<span highlight="lightblue">{{ post.title | titlecase }}</span>Je pense que dans le cas présent, le meilleur choix est de laisser color comme @Input , car ça laisse l'option de ne pas passer de couleur en paramètre si on souhaite garder la couleur par défaut. Je trouve que ça laisse le plus de flexibilité.
Voyons maintenant comment réagir à des événements dans la Directive !
Il peut être très intéressant, pour une Directive, de pouvoir réagir aux événements HTML émanant de l'élément sur lequel elle est placée. Angular vous permet de faire exactement ça avec le décorateur @HostListener :
import { AfterViewInit, Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';
@Directive({
selector: '[highlight]'
})
export class HighlightDirective implements AfterViewInit {
@Input() color = 'yellow';
constructor(private el: ElementRef,
private renderer: Renderer2) {}
ngAfterViewInit() {
this.setBackgroundColor(this.color);
}
setBackgroundColor(color: string) {
this.renderer.setStyle(this.el.nativeElement, 'background-color', color);
}
@HostListener('mouseenter') onMouseEnter() {
this.setBackgroundColor('lightgreen');
}
@HostListener('mouseleave') onMouseLeave() {
this.setBackgroundColor(this.color);
}
@HostListener('click') onClick() {
this.color = 'lightgreen';
}
}Dans cet exemple :
quand la souris entre sur l'élément, vous changez sa couleur de fond en lightgreen ;
si la souris sort sans avoir cliqué, la couleur revient à sa couleur par défaut ;
si l'utilisateur clique sur l'élément, la couleur par défaut est changée en lightgreen , ce qui donne l'effet de "valider" ce qui est cliqué : l'élément restera lightgreen en permanence.
La Directive est une arme essentielle dans l'arsenal des développeurs Angular, donc pensez-y lorsque vous aurez besoin d'apporter du comportement à des éléments HTML de votre application.
Une Directive peut être placée sur différents types d'élément HTML pour leur apporter un comportement supplémentaire.
Le selector d'une Directive attribut doit s'écrire entre crochets [] .
Une Directive peut injecter l'élément HTML sur lequel elle est placée avec ElementRef , et interagir avec cet élément avec Renderer2 .
Une Directive peut comporter des @Input pour accepter des paramètres.
Une Directive peut écouter les événements émanant de son élément grâce au décorateur @HostListener .
Vous avez implémenté un resolver pour récupérer des données entre deux routes.
Vous avez construit un component totalement réutilisable.
Vous avez créé vos propres Pipes.
Vous avez développé votre propre Directive.
Je vous ai concocté un quiz pour valider ce que vous avez appris de cette partie. Après, je vous donne rendez-vous dans la partie 2 pour découvrir les animations !