Guides approfondis
Directives

Directives d'attribute

Les directives d'attribute modifient l'apparence ou le comportement des éléments du DOM et des composants Angular.

Utiliser les bindings de template pour un comportement ponctuel

La syntaxe de template d'Angular couvre déjà la modification des classes, des styles, des propriétés et des événements d'un seul élément :

Les directives d'attribute sont utiles quand vous voulez regrouper ce type de comportement dans une unité réutilisable que vous pouvez appliquer à n'importe quel élément ou composant.

Créer une directive d'attribute

Une directive d'attribute personnalisée est une classe JavaScript dotée du décorateur @Directive(). Le selector du décorateur définit l'attribut qui applique la directive. Les crochets en font un attribute selector : la directive correspond donc aux éléments qui portent cet attribut. Par convention, utilisez un préfixe comme app pour éviter les collisions de noms :

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

@Directive({
  selector: '[appHighlight]',
})
export class HighlightDirective {}

Utile : La commande CLI ng generate directive génère une directive accompagnée de son fichier de test.

Une directive peut modifier son host de manière déclarative avec des host bindings, ou de manière impérative grâce à une référence au host element. Cet exemple injecte ElementRef et accède à l'élément via sa propriété nativeElement pour passer l'arrière-plan en jaune :

highlight.directive.ts

import {Directive, ElementRef, inject} from '@angular/core';

@Directive({
  selector: '[appHighlight]',
})
export class HighlightDirective {
  private el = inject(ElementRef);

  constructor() {
    this.el.nativeElement.style.backgroundColor = 'yellow';
  }
}

Important : Les directives ne prennent pas en charge les namespaces.

À éviter
<p app:Highlight>This is invalid</p>

Appliquer une directive d'attribute

Pour appliquer la directive, ajoutez son selector comme attribut sur un élément :

app.component.html

<p appHighlight>Highlight me!</p>

Angular crée une instance de HighlightDirective pour cet élément <p>, injecte une référence à l'élément et passe son arrière-plan en jaune.

Gérer les événements utilisateur

Pour répondre aux interactions de l'utilisateur, liez les événements du host element à des méthodes de gestion via la propriété host du décorateur @Directive(). La directive suivante met en surbrillance le host element tant que le pointeur le survole et retire la surbrillance quand le pointeur en sort :

highlight.directive.ts

import {Directive, ElementRef, inject} from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
export class HighlightDirective {
  private el = inject(ElementRef);

  onMouseEnter() {
    this.highlight('yellow');
  }

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

La propriété host associe les événements mouseenter et mouseleave aux méthodes onMouseEnter() et onMouseLeave(), qui délèguent à un helper highlight() chargé de définir la couleur d'arrière-plan du host element. Pour en savoir plus sur les bindings d'événements du host, consultez lier des valeurs au host element.

Accepter des valeurs en input

Comme les composants, les directives acceptent des inputs via la fonction input(). Donnez à un input le même nom que le selector pour qu'un seul binding applique la directive et lui transmette une valeur :

highlight.directive.ts

appHighlight = input('');

Lisez l'input en l'appelant comme un signal, et utilisez une valeur par défaut quand aucune couleur n'est définie :

highlight.directive.ts

onMouseEnter() {
  this.highlight(this.appHighlight() || 'red');
}

Dans le template, liez la valeur au selector. Comme l'input porte le même nom que le selector, [appHighlight] applique la directive et définit sa valeur. Ici, color est une propriété du composant :

app.component.html

<p [appHighlight]="color">Highlight me!</p>

app.component.ts

export class AppComponent {
  color = '';
}

Une directive peut déclarer plusieurs inputs. La directive suivante ajoute un input defaultColor, puis se rabat successivement sur appHighlight, defaultColor et enfin red :

highlight.directive.ts

import {Directive, ElementRef, inject, input} from '@angular/core';

@Directive({
  selector: '[appHighlight]',
  host: {
    '(mouseenter)': 'onMouseEnter()',
    '(mouseleave)': 'onMouseLeave()',
  },
})
export class HighlightDirective {
  private el = inject(ElementRef);

  defaultColor = input('');

  appHighlight = input('');

  onMouseEnter() {
    this.highlight(this.appHighlight() || this.defaultColor() || 'red');
  }

  onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

Liez les deux inputs sur le même élément. Comme defaultColor reçoit une chaîne statique plutôt qu'une expression dynamique, il n'a pas besoin de crochets :

app.component.html

<p [appHighlight]="color" defaultColor="violet">Highlight me too!</p>

Désactiver le traitement d'Angular avec NgNonBindable

Pour empêcher l'évaluation des expressions dans le navigateur, ajoutez ngNonBindable au host element. ngNonBindable désactive l'interpolation, les directives et le binding dans les templates.

Dans l'exemple suivant, l'expression {{ 1 + 1 }} s'affiche telle qu'elle apparaît dans votre éditeur de code, et n'affiche pas 2.

app.component.html

<p>Use ngNonBindable to stop evaluation.</p>
<p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p>

Appliquer ngNonBindable à un élément arrête le binding pour les éléments enfants de cet élément. Cependant, ngNonBindable laisse les directives fonctionner sur l'élément auquel vous appliquez ngNonBindable. Dans l'exemple suivant, la directive appHighlight reste active, mais Angular n'évalue pas l'expression {{ 1 + 1 }}.

app.component.html

<h3>ngNonBindable with a directive</h3>
<div ngNonBindable [appHighlight]="'yellow'">
  This should not evaluate: {{ 1 + 1 }}, but will highlight yellow.
</div>

Si vous appliquez ngNonBindable à un élément parent, Angular désactive l'interpolation et tout type de binding, comme le property binding ou l'event binding, pour les enfants de cet élément.

Et ensuite ?