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 !)
Dans cet article vous allez découvrir les directives d'Angular, comment les utiliser et dans quel contexte.
Qu’est-ce qu’une directive ?
Pour commencer, une définition : les directives d'Angular sont des classes qui ajoutent un comportement supplémentaire aux éléments du DOM.
Ces directives s'appliqueront dans vos fichiers HTML, sur les balises de composants et/ou balises HTML.
Liste complète des directives natives
Vous pouvez retrouvez la liste exhaustive de toutes les directives natives d'Angular sur la documentation, en cliquant sur ce lien : Liste des directives natives
Les différents types de directives
On dit qu'une directive est structurelle lorsqu'elle modifie la structure du DOM, c'est-à-dire lorsqu'on ajoute, supprime ou déplace une balise.
Lorsqu'on dit par contre qu'une directive est une directive d'attribut, on parle d'une directive qui change un attribut de l'élément du DOM, sans modifier la structure du DOM dans son ensemble.
On peut aussi parler de directive native ou intégrée lorsqu'elle est fournie par Angular.
Structural directives
Commençons donc par voir les Structural directives qui permettent de travailler sur la structure de votre HTML. Ces directives sont fournies par Angular et vous permettent d'ajouter, retirer ou déplacer les éléments du DOM.
Elles sont très peu nombreuses donc faciles à retenir. Tant mieux, parce qu'elles sont importante à maitriser.
En voici la liste complète :
- *NgIf
- *NgFor
- [NgSwitch], *NgSwitchCase, *NgSwitchDefault
Exemples d'utilisation
Voyons comment utiliser ces 3 directives :
NgIf
Charge une balise sur la page uniquement si la condition est vraie.
1
<p *ngIf="condition">Affiche ce paragraphe si la condition est vraie.</p>
NgFor
Permet de dupliquer une balise.
1
2
3
<ol>
<li *ngFor="let user of users"> {{user.name}} {{user.lastname}} </li>
</ol>
Dans cet exemple, la balise <li></li> est dupliquée autant de fois qu'il y a de user dans la variable users. Chaque user devient alors accessible depuis la variable définie dans le let du *ngFor
NgSwitch
1
2
3
4
5
<div [ngSwitch]="expression à évaluer">
<p *ngSwitchCase="valeur_1"> Ce paragraphe est affiché si l’expression évaluée == valeur_1.</p>
<p *ngSwitchCase="valeur_2"> Affiche ce paragraphe si l’expression à évaluer == valeur_2.</p>
<p *ngSwitchDefault> Affiche ce paragraphe si aucune des valeurs n'est égale à l'expression.</p>
</div>
C'est tout pour les directives structurelles !
Attribute directives
Voyons maintenant les Attributes directives. Ce sont des classes TS ayant comme décorateur “@Directive” permettant d'agir sur les attributs d’éléments du DOM.
Directives d'attributs intégrées
Avec les directives d’attributs intégrées d'Angular, vous pouvez gérer certains éléments de votre DOM tels que les formulaires, les styles et les classes.
On retrouve notamment :
- NgClass
- NgStyle
- NgModel
Exemples d'utilisation
NgClass
On peut ajouter ou supprimer plusieurs classes CSS simultanément avec ngClass. Sur un élément que vous souhaitez styliser ajoutez un ngClass [ngClass] et si l’expression évaluée renvoie true, alors Angular appliquera la classe.
1
2
3
4
<div [ngClass]="{ 'card' : isCard && isFirst,
'card bg-blue' : isCard && isSecond,
'': false }">
</div>
NgStyle
NgStyle permet de définir plusieurs styles, selon l'état du composant.
Dans votre composant :
1
2
3
4
5
6
7
8
9
10
11
12
currentStyles: Record<string, string> = {};
setCurrentStyles() {
etatUn: boolean;
etatDeux: boolean = true;
etatTrois: boolean;
this.currentStyles = {
'font-style': this.etatUn ? 'italic' : 'normal',
'font-weight': !this.etatDeux ? 'bold' : 'normal',
'font-size': this.etatTrois ? '24px' : '12px'
};
}
Puis côté html, on applique les styles à la balise en les passant à la directive ngStyle.
1
2
3
4
<div [ngStyle]="currentStyles">
Le texte de cette div est initialement en italique,
d'épaisseur normale, et de grande taille (24px).
</div>
NgModel
La directive NgModel nous permet d'agir sur l'attribut "value" de nos balises
C'est dans l'attribut value qu'on retrouve la valeur saisie par un utilisateur dans une balise input.
NgModel s'utilise donc sur un input pour réaliser une liaison bidirectionnelle entre votre template et votre component.
1
2
<label for="example-ngModel">[(ngModel)]:</label>
<input [(ngModel)]="currentItem.name" id="example-ngModel">
Une variable annotée "ngModel" sera dite "two-way bindée". Donc si l'utilisateur modifie la donnée côté template, elle est aussitôt modifié en temps réel dans le component. Et vice-versa si vous changez la valeur depuis le component, la valeur sera actualisée instantanément sur le template.
Toutefois, attention car avec cette syntaxe on ne peut définir qu’une seule propriété liée. C’est à dire que la valeur de l’input ne peut pas être liée à 2 attributs de composant ou +.
Pour ce cas précis vous devrez utiliser les reactive forms. Nous les verrons dans un prochain article dédié aux formulaires.
Créer sa propre directive d'attribut
Générer le squelette de la directive
En premier lieu, pour créer une directive, utilisez la commande de la CLI :
1
2
ng generate directive <nom>
ng g d <nom>
Cela aura pour effet de créer les fichiers typescript :
- src/app/<nom>.directive.ts
- un fichier de test correspondant : src/app/<nom>.directive.spec.ts
Et également de déclarer la classe directive dans le fichier AppModule.
Voici le contenu généré par la CLI dans le fichier src/app/<nom>.directive.ts :
1
2
3
4
5
6
7
8
import { Directive } from '@angular/core';
@Directive({
selector: '[app<Nom>]'
})
export class <nom>Directive {
constructor() { }
}
La propriété selector du décorateur spécifie le sélecteur d'attribut de la directive, [app-
Vous pouvez donc désormais écrire la logique votre directive !
Ecrire la logique de votre directive
Voici une directive qui colore en bleu le background de l'élément DOM sur lequel on l'utilise :
1
2
3
4
5
6
7
8
9
10
11
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[appAnyDirective]'
})
export class AnyDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'blue';
}
}
Vous remarquez que l'on a importé ElementRef depuis @angular/core. ElementRef est un wrapper qui nous permet d’accéder directement à l'élément du DOM.
Donc si vous ajoutez un ElementRef dans le constructor(), Angular vous y injecte une référence à l'élément DOM hôte, l'élément auquel vous appliquez appAnyDirective ! Vous pouvez ensuite manipuler votre objet du DOM via cette référence.
Utiliser votre directive d'attribut
Finalement, pour utiliser la directive, ajoutez comme attribut à la balise le nom de la directive que vous avez précédemment créée.
1
<p appAnyDirective>Arrière plan bleu</p>.
Configuration des directives
Le paramètre selector
Le paramètre selector est le plus important car il va indiquer comment on utilisera la directive. En effet, selon la syntaxe qu’on utilisera, la directive sera représentée par un objet du DOM, une classe CSS ou un attribut dans une balise HTML.
Le selector se paramètre dans le décorateur @Directive() :
1
2
3
4
@Directive({
selector: <valeur>
})
export class AnyDirective {}
Directive utilisée en tant que balise
selector: 'any-directive'
Dans ce cas-ci, la directive doit être utilisée comme élément dans le template :
1
<any-directive></any-directive>
D'ailleurs, saviez-vous que Component est une classe fille de Directive (Component extends Directive) ?
Un Component n'est en fait qu'une directive à laquelle on a associé une vue (template HTML)
Directive utilisée en tant qu'attribut
selector: '[any-directive]'
C'est le cas le plus courant ! En effet le plus souvent, les directives sont utilisées en tant qu'attribut.
Dans ce cas-ci, la directive doit être utilisée comme attribut de la balise :
1
<div any-directive></div>
Optionnellement, on peut aussi vouloir passer une valeur à cet attribut :
1
<div [any-directive]="valeur"></div>
Dans ce cas là on récupère la valeur passé grâce à un input (de même nom que le selector) dans la directive :
1
@Input() appAnyDirective= '';
Directive utilisée en tant que classe CSS
selector: '.any-directive'
Dans cet exemple on utilise la directive sous forme de classe CSS.
1
<div class="any-directive"></div>
Le paramètre inputs
Si je décide d'utiliser ma directive en tant que balise, elle pourra gérer des entrées/sorties.
Inputs permet donc d’utiliser des paramètres d’entrée dans la directive. Le nom du paramètre doit être sous forme de chaîne de caractères dans l'attribut inputs :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Directive, ElementRef, Renderer2, OnInit } from '@angular/core';
@Directive({
selector: 'custom-directive',
inputs: [ 'textToDisplay' ]
})
export class CustomDirective implements OnInit {
textToDisplay: string;
constructor(private elem: ElementRef, private renderer: Renderer2) {}
ngOnInit(): void {
let newText = this.renderer.createText(this.textToDisplay);
this.renderer.appendChild(this.elem.nativeElement, newText);
}
}
Ici, la propriété ElementRef.nativeElement nous permet d’accéder directement à l’objet du DOM.
Le paramètre de type Renderer2 est une classe permettant de manipuler les éléments du DOM.
Que faisons-nous concrètement ? On transmet la valeur à partir du template, pour qu'elle soit utilisée dans la directive :
1
<custom-directive textToDisplay="Valeur défini depuis le template"></custom-directive>
Le paramètre outputs
Output permet de déclarer des événements de la directive auxquels le composant peut s’abonner. Le nom de l'événement doit être sous forme de chaîne de caractères dans le paramètre outputs :
1
<custom-directive textToDisplay="Valeur défini depuis le template"></custom-directive>
Exemple
Prenons l'exemple d'une directive qui crée un bouton capable d'émettre un événement.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Directive, ElementRef, Renderer2 } from '@angular/ core';
@Directive({
selector: 'custom-directive',
outputs: [ 'anyEvent' ]
})
export class CustomDirective {
anyEvent: EventEmitter<string> = new EventEmitter<string>();
constructor(private elem: ElementRef, private renderer: Renderer2) {
let Button = this.renderer.createElement('button');
let buttonText = this.renderer.createText('Cliquez');
// On ajoute du texte au bouton
this.renderer.appendChild(Button, buttonText);
// On ajoute la callback correspondant au clique sur le bouton
this.renderer.listen(Button, 'click', () => this.buttonClicked());
// On ajoute le bouton à l'élément (le composant)
this.renderer.appendChild(this.elem.nativeElement, Button);
}
private buttonClicked(): void {
this.anyEvent.emit('message');
}
}
Le paramètre providers
Enfin, nous avons le paramètre providers pour injecter des services dans la directive. Voir l’article sur l’injection de dépendance pour plus de détails.
Conclusion
Pour conclure, vous avez maintenant les connaissances qu’il faut pour savoir quand et pourquoi utiliser les directives, n'hésitez pas à poser des questions en commentaires !
Sources
- Cdièse - Angular Directive
- Angular - Attribute Directive
- Différence entre @Directive().inputs et @Input() - @Directive().inputs And @Input() Are Not Functionally Equivalent In Angular 7.2.13
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.