Apprendre à programmer avec le framework Angular

Les directives

William KOZA

À travers ce tutoriel, nous allons apprendre à utiliser les directives qui sont présentes partout dans l'architecture Angular. Les Components sont des directives à la seule différence qu'ils possèdent une fonctionnalité de templating. En TypeScript, une directive est une classe à laquelle on applique le décorateur @Directive. Il existe deux sortes de directives :

- Les directives structurelles : elles ont pour but de modifier le DOM en ajoutant, enlevant ou replaçant un élément du DOM.

- Les attribute directives : elles ont pour but de modifier l'apparence ou le comportement d'un élément.

Commentez

- Titre : Apprendre à programmer avec le framework Angular

- Auteur : William KOZA

- Parution : 29 novembre 2016

- Mise à jour : 29 novembre 2016

- Public visé :

- Licence : Copyright ® 2016 William KOZA. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Les différentes directives

- I-A. Les directives structurelles

- I-B. Les attribute directives

- II. Construire ses directives

- II-A. Création de notre Directive

- II-B. Ajouter du component grâce aux events JavaScript

- III. Remerciements

I - Les différentes directives

I-A - Les directives structurelles

Je ne vais pas lister toutes les directives structurelles proposées par Angular, mais nous allons quand même en étudier une pour l'exemple : ngIf. ngIf permet de supprimer ou de recréer l'élément courant suivant l'expression passée en paramètre. Si l'expression assignée au ngIf est évaluée à false alors l'élément sera supprimé du DOM, puis l'élément sera recréé si l'expression est évaluée à true. Voici un exemple de template utilisant cette directive :

1. <div *ngIf="1 > 0"> Afficher la div</div>

Afficher la div sera bien affiché puisque l'expression 1 > 0 vaut bien true. Je vous propose maintenant d'inverser le sens de l'expression de sorte que 1 < 0. Dans ce cas, notre div disparait totalement du DOM.

Vous vous posez sans doute la question du symbole astérisque (*) devant notre directive. Les directives structurelles telles que *ngIf, *ngForet *ngSwitchCase sont toutes encadrées par une balise HTML5 <template>. L'astérisque (*) permet de lire et d'écrire plus facilement des directives qui ont vocation à changer la mise en page HTML. Prenons l'exemple de notre directive ngIf : lorsque Angular va détecter (*) devant *ngIf, il va opérer différentes transformations pour arriver au résultat suivant :

1. <template [ngIf]="1 > 0"><div> Afficher la div</div></template>

Notre directive ngIf sera donc maintenant un template HTML 5 et pourra interpréter l'expression passée en paramètre grâce au Property Binding (usage des [ ]).

I-B - Les attribute directives

Une bonne candidate pour comprendre les attribute directives est la directive ngStyle. Cette attribut directive se charge de modifier l'apparence de l'élément porteur. Lorsque l'on utilise cette directive, il est nécessaire de la placer entre crochets comme ceci : [ngStyle]. Ce n'est pas forcément le cas de toutes les attribute directives. ngStyle attend une valeur en paramètre, elle utilise ce que l'on appelle le Property Binding que nous reverrons plus tard. Voici un exemple de template utilisant cette directive :

1. <div [ngStyle]="{color:'red'}">Learn Angular</div>

Dans ce cas, il n'y a pas de modification de structure. La directive transforme juste notre [ngStyle]="{color:'red'}" en style="color: red;".

II - Construire ses directives

Je vous propose maintenant de créer notre propre directive pour bien en comprendre le fonctionnement. Voici notre cahier des charges :

Réaliser une directive qui permet de modifier la couleur lorsque le pointeur de la souris passe dessus.

À la lecture de cette spécification « post-it », une réunion a été organisée avec la maitrise d'ouvrage. Concernant la couleur, aucun compromis n'a été trouvé après 3 heures de débat même si le rouge intéressait pas mal d'intervenants. Pour contenter tout le monde, notre Directive devra proposer une couleur par défaut (le rouge) lors de l'affichage et une autre couleur paramétrable pour le mouse enter et tout cela avec le même budget.

À la lecture du compte rendu de cette réunion, nous pouvons déjà nous dire que nous sommes face à une attribute directive.

II-A - Création de notre Directive

Commençons par créer notre directive à l'aide d'Angular-CLI avec la commande :

Cela nous donne le code suivant pour notre directive :

1. import { Directive } from '@angular/core';

3. @Directive({

4. selector: '[appHighlight]'

5. })

7. export class HighlightDirective {

9. constructor() { }

11. }

Pourquoi Angular-CLI ajoute des [ … ] à notre sélecteur ? Angular utilise les sélecteurs CSS pour identifier l'élément HTML dans un template. Grâce à cette annotation, Angular sera capable de localiser tous les éléments qui possèdent l'attribut nommé appHighLight.

La première étape consiste à appliquer la couleur par défaut lorsque l'on applique cette directive. Comme nous sommes dans une classe, nous pouvons utiliser le constructeur comme ceci :

1. import {Directive, Renderer2, ElementRef} from '@angular/core';

3. @Directive(

4. {

5. selector: '[appHighlight]'

6. })

7. export class HighlightDirective {

9. constructor(el: ElementRef, renderer: Renderer2) {

11. renderer.setStyle(el.nativeElement, 'color', 'red');

12. }

13. }

ElementRef est injecté dans le constructeur par Angular afin de récupérer l'élément du DOM dans notre classe. Grâce à cette injection, il est possible de modifier le style de l'élément grâce à Renderer2. Vous pouvez tester votre directive dans le template d'un de vos Components comme ceci :

1. <div appHighlight>Texte en hightlight</div>

Bon, on ne va pas se mentir, le résultat est plutôt décevant. Le texte est rouge certes, mais cela s'arrête là. On va dynamiser tout cela alors…

II-B - Ajouter du component grâce aux events JavaScript

Notre directive doit réagir à deux évènements :

- Lorsque le pointeur de la souris est sur l'élément : la couleur du texte doit passer à une couleur paramétrable.

- Lorsque le pointeur de la souris quitte l'élément : la couleur du texte doit redevenir rouge.

Angular propose le décorateur @HostListener pour positionner des Listeners sur l'élément. Il prend en paramètre l'évènement que l'on veut écouter. Notre classe devient alors :

1. import {Directive, Renderer2, ElementRef, HostListener} from '@angular/core';

4. @Directive({

5. selector: '[appHighlight]'

6. })

8. export class HighlightDirective {

10. constructor(el: ElementRef, renderer: Renderer2) {

11. renderer.setStyle(el.nativeElement, 'color', 'red');

12. }

14. @HostListener('mouseenter') onMouseEnter() {

15. console.log('mouseenter')

16. }

18. @HostListener('mouseleave') onMouseLeave() {

19. console.log('mouseleave')

20. }

21. }

À l'exécution, si l'on ouvre la fenêtre de debug JavaScript, on remarque que notre div réagit bien aux évènements mouseenter et mouseleave.

Il ne nous reste plus qu'à définir la couleur paramétrable grâce à un autre décorateur Angular : le décorateur @Input. Ce décorateur permet de lier le paramètre passé à une propriété de la classe de la Directive. Il est possible de passer en paramètre un alias dans le cas où la propriété de la classe n'a pas le même que l'attribut de la Directive. Voici notre Directive finale :

1. import {Directive, Renderer2, ElementRef, HostListener, Input} from '@angular/core';

3. @Directive({

4. selector: '[appHighlight]'

5. })

6. export class HighlightDirective {

8. @Input('appHighlight') highlightColor: string;

10. private _defaultColor = 'red';

12. constructor(private _el: ElementRef, private _renderer: Renderer2) {

13. this._renderer.setStyle(this._el.nativeElement, 'color', this._defaultColor);

14. }

16. @HostListener('mouseenter') onMouseEnter() {

17. this._renderer.setStyle(this._el.nativeElement, 'color', this.highlightColor);

18. }

20. @HostListener('mouseleave') onMouseLeave() {

21. this._renderer.setStyle(this._el.nativeElement, 'color', this._defaultColor);

22. }

23. }

Grâce à ce code, il est possible d'utiliser notre Directive comme ceci :

1. <div [appHighlight]="'yellow'">Texte en highlight</div>

La classe a été un peu remaniée pour coller au besoin :

- Le constructeur a été modifié pour permettre d'utiliser ses paramètres dans toute la classe. Le fait de mettre la portée devant les paramètres est un accélérateur de développement qui permet de faire l'équivalent d'un this._el = _el. C'est une spécificité TypeScript bien pratique.

- Le @Input a été ajouté. Il permet de récupérer notre couleur passée en paramètre de notre directive.

- Nos @HostListener ont été modifiés pour permettre le changement de couleur comme c'était le cas avec notre constructeur.

Voilà, maintenant, vous êtes prêts à faire vos propres Directives Angular !

III - Remerciements

Tous mes remerciements à toute l'équipe de developpez.com, et plus particulièrement Laethy pour la relecture technique et f-leb pour la relecture orthographique.