Guias Detalhados
Directives

Attribute directives

Mude a aparência ou comportamento de elementos DOM e components Angular com attribute directives.

Construindo uma attribute directive

Esta seção orienta você na criação de uma directive de destaque que define a cor de fundo do elemento host para amarelo.

  1. Para criar uma directive, use o comando CLI ng generate directive.

    ng generate directive highlight

    O CLI cria src/app/highlight.directive.ts, um arquivo de teste correspondente src/app/highlight.directive.spec.ts.

    src/app/highlight.directive.ts

    import {Directive} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {}

    A propriedade de configuração do decorator @Directive() especifica o seletor de atributo CSS da directive, [appHighlight].

  2. Importe ElementRef de @angular/core. ElementRef concede acesso direto ao elemento DOM host através de sua propriedade nativeElement.

  3. Adicione ElementRef no constructor() da directive para injetar uma referência ao elemento DOM host, o elemento ao qual você aplica appHighlight.

  4. Adicione lógica à classe HighlightDirective que define o fundo como amarelo.

src/app/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';  }}

ÚTIL: Directives não suportam namespaces.

src/app/app.component.avoid.html (não suportado)

<p app:Highlight>This is invalid</p>

Aplicando uma attribute directive

  1. Para usar a HighlightDirective, adicione um elemento <p> ao template HTML com a directive como um atributo.

src/app/app.component.html

<h1>My First Attribute Directive</h1><p appHighlight>Highlight me!</p><p appHighlight="yellow">Highlighted in yellow</p><p [appHighlight]="'orange'">Highlighted in orange</p><p [appHighlight]="color">Highlighted with parent component's color</p>

O Angular cria uma instância da classe HighlightDirective e injeta uma referência ao elemento <p> no constructor da directive, que define o estilo de fundo do elemento <p> como amarelo.

Manipulando eventos do usuário

Esta seção mostra como detectar quando um usuário passa o mouse sobre o elemento ou sai dele e responder definindo ou limpando a cor de destaque.

  1. Importe HostListener de '@angular/core'.

src/app/highlight.directive.ts (imports)

import {Directive, ElementRef, HostListener, inject} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  @HostListener('mouseenter') onMouseEnter() {    this.highlight('yellow');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  1. Adicione dois event handlers que respondem quando o mouse entra ou sai, cada um com o decorator @HostListener().

src/app/highlight.directive.ts (mouse-methods)

import {Directive, ElementRef, HostListener, inject} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  @HostListener('mouseenter') onMouseEnter() {    this.highlight('yellow');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}

Inscreva-se em eventos do elemento DOM que hospeda uma attribute directive, o <p> neste caso, com o decorator @HostListener().

ÚTIL: Os handlers delegam para um método auxiliar, highlight(), que define a cor no elemento DOM host, el.

A directive completa é a seguinte:

src/app/highlight.directive.ts

import {Directive, ElementRef, HostListener, inject} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  @HostListener('mouseenter') onMouseEnter() {    this.highlight('yellow');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}

A cor de fundo aparece quando o ponteiro passa sobre o elemento de parágrafo e desaparece quando o ponteiro se move para fora.

Second Highlight

Passando valores para uma attribute directive

Esta seção orienta você a definir a cor de destaque ao aplicar a HighlightDirective.

  1. Em highlight.directive.ts, importe Input de @angular/core.

src/app/highlight.directive.ts (imports)

import {Directive, ElementRef, HostListener, inject, input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  appHighlight = input('');  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight() || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  1. Adicione uma propriedade input appHighlight.

    src/app/highlight.directive.ts

    import {Directive, ElementRef, HostListener, inject, input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  appHighlight = input('');  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight() || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}

    A função input() adiciona metadados à classe que torna a propriedade appHighlight da directive disponível para binding.

  2. Em app.component.ts, adicione uma propriedade color ao AppComponent.

src/app/app.component.ts (class)

import {Component} from '@angular/core';import {HighlightDirective} from './highlight.directive';@Component({  selector: 'app-root',  templateUrl: './app.component.1.html',  imports: [HighlightDirective],})export class AppComponent {  color = 'yellow';}
  1. Para aplicar simultaneamente a directive e a cor, use property binding com o seletor da directive appHighlight, definindo-o igual a color.

    src/app/app.component.html (color)

    <h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

    O attribute binding [appHighlight] executa duas tarefas:

    • Aplica a directive de destaque ao elemento <p>
    • Define a cor de destaque da directive com um property binding

Definindo o valor com entrada do usuário

Esta seção orienta você a adicionar botões de opção para vincular sua escolha de cor à directive appHighlight.

  1. Adicione marcação a app.component.html para escolher uma cor da seguinte forma:

src/app/app.component.html (v2)

<h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>
  1. Revise o AppComponent.color para que ele não tenha valor inicial.

src/app/app.component.ts (class)

import {Component} from '@angular/core';import {HighlightDirective} from './highlight.directive';@Component({  selector: 'app-root',  templateUrl: './app.component.html',  imports: [HighlightDirective],})export class AppComponent {  color = '';}
  1. Em highlight.directive.ts, revise o método onMouseEnter para que ele primeiro tente destacar com appHighlight e volte para red se appHighlight for undefined.

src/app/highlight.directive.ts (mouse-enter)

import {Directive, ElementRef, HostListener, inject, input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  appHighlight = input('');  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight() || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  1. Sirva sua aplicação para verificar que o usuário pode escolher a cor com os botões de opção.
Gif animado da directive de destaque refatorada mudando de cor de acordo com o botão de opção que o usuário seleciona

Binding para uma segunda propriedade

Esta seção orienta você a configurar sua aplicação para que o desenvolvedor possa definir a cor padrão.

  1. Adicione uma segunda propriedade Input() à HighlightDirective chamada defaultColor.

src/app/highlight.directive.ts (defaultColor)

import {Directive, ElementRef, HostListener, inject, input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  defaultColor = input('');  appHighlight = input('');  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight() || this.defaultColor() || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  1. Revise o onMouseEnter da directive para que ele primeiro tente destacar com o appHighlight, depois com o defaultColor, e volte para red se ambas as propriedades forem undefined.

src/app/highlight.directive.ts (mouse-enter)

import {Directive, ElementRef, HostListener, inject, input} from '@angular/core';@Directive({  selector: '[appHighlight]',})export class HighlightDirective {  private el = inject(ElementRef);  defaultColor = input('');  appHighlight = input('');  @HostListener('mouseenter') onMouseEnter() {    this.highlight(this.appHighlight() || this.defaultColor() || 'red');  }  @HostListener('mouseleave') onMouseLeave() {    this.highlight('');  }  private highlight(color: string) {    this.el.nativeElement.style.backgroundColor = color;  }}
  1. Para fazer binding com AppComponent.color e voltar para "violet" como a cor padrão, adicione o seguinte HTML. Neste caso, o binding defaultColor não usa colchetes, [], porque é estático.

    src/app/app.component.html (defaultColor)

    <h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

    Assim como com components, você pode adicionar múltiplos property bindings de directive a um elemento host.

A cor padrão é vermelho se não houver binding de cor padrão. Quando o usuário escolhe uma cor, a cor selecionada se torna a cor de destaque ativa.

Gif animado da directive de destaque final que mostra cor vermelha sem binding e violeta com a cor padrão definida. Quando o usuário seleciona a cor, a seleção tem precedência.

Desativando o processamento do Angular com NgNonBindable

Para prevenir a avaliação de expressões no navegador, adicione ngNonBindable ao elemento host. ngNonBindable desativa interpolation, directives e binding em templates.

No exemplo a seguir, a expressão {{ 1 + 1 }} renderiza exatamente como aparece no seu editor de código, e não exibe 2.

src/app/app.component.html

<h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

Aplicar ngNonBindable a um elemento interrompe o binding para os elementos filhos desse elemento. No entanto, ngNonBindable ainda permite que directives funcionem no elemento onde você aplica ngNonBindable. No exemplo a seguir, a directive appHighlight ainda está ativa, mas o Angular não avalia a expressão {{ 1 + 1 }}.

src/app/app.component.html

<h1>My First Attribute Directive</h1><h2>Pick a highlight color</h2><div>  <input type="radio" name="colors" (click)="color='lightgreen'">Green  <input type="radio" name="colors" (click)="color='yellow'">Yellow  <input type="radio" name="colors" (click)="color='cyan'">Cyan</div><p [appHighlight]="color">Highlight me!</p><p [appHighlight]="color" defaultColor="violet">  Highlight me too!</p><hr><h2>Mouse over the following lines to see fixed highlights</h2><p [appHighlight]="'yellow'">Highlighted in yellow</p><p appHighlight="orange">Highlighted in orange</p><hr><h2>ngNonBindable</h2><p>Use ngNonBindable to stop evaluation.</p><p ngNonBindable>This should not evaluate: {{ 1 + 1 }}</p><h3>ngNonBindable with a directive</h3><div ngNonBindable [appHighlight]="'yellow'">This should not evaluate: {{ 1 +1 }}, but will highlight yellow.</div>

Se você aplicar ngNonBindable a um elemento pai, o Angular desativa interpolation e binding de qualquer tipo, como property binding ou event binding, para os filhos do elemento.