Guías Detalladas
Directivas

Directivas de atributo

Cambia la apariencia o comportamiento de elementos DOM y componentes Angular con directivas de atributo.

Construyendo una directiva de atributo

Esta sección te guía a través de la creación de una directiva de resaltado que establece el color de fondo del elemento host en amarillo.

  1. Para crear una directiva, usa el comando CLI ng generate directive.

    ng generate directive highlight

    El CLI crea src/app/highlight.directive.ts, un archivo de prueba correspondiente src/app/highlight.directive.spec.ts.

    src/app/highlight.directive.ts

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

    La propiedad de configuración del decorador @Directive() especifica el selector de atributo CSS de la directiva, [appHighlight].

  2. Importa ElementRef desde @angular/core. ElementRef otorga acceso directo al elemento DOM host a través de su propiedad nativeElement.

  3. Añade ElementRef en el constructor() de la directiva para inyectar una referencia al elemento DOM host, el elemento al que aplicas appHighlight.

  4. Añade lógica a la clase HighlightDirective que establece el fondo a amarillo.

    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: Las directivas no soportan espacios de nombres.

src/app/app.component.avoid.html (no soportado)

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

Aplicando una directiva de atributo

  1. Para usar HighlightDirective, añade un elemento <p> a la plantilla HTML con la directiva como 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>

Angular crea una instancia de la clase HighlightDirective e inyecta una referencia al elemento <p> en el constructor de la directiva, que establece el estilo de fondo del elemento <p> a amarillo.

Manejando eventos de usuario

Esta sección te muestra cómo detectar cuando un usuario pasa el mouse sobre o fuera del elemento y responder estableciendo o limpiando el color de resaltado.

  1. Importa HostListener desde '@angular/core'.

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

    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;  }}
  2. Añade dos manejadores de eventos que responden cuando el mouse entra o sale, cada uno con el decorador @HostListener().

    src/app/highlight.directive.ts (métodos-mouse)

    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;  }}

Suscríbete a eventos del elemento DOM que aloja una directiva de atributo, el <p> en este caso, con el decorador @HostListener().

ÚTIL: Los manejadores delegan a un método auxiliar, highlight(), que establece el color en el elemento DOM host, el.

La directiva completa es la siguiente:

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;  }}

El color de fondo aparece cuando el puntero se desplaza sobre el elemento de párrafo y desaparece cuando el puntero se mueve fuera.

Segundo Resaltado

Pasando valores a una directiva de atributo

Esta sección te guía a través de establecer el color de resaltado mientras aplicas HighlightDirective.

  1. En highlight.directive.ts, importa Input desde @angular/core.

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

    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;  }}
  2. Añade una propiedad 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;  }}

    La función input() añade metadatos a la clase que hace que la propiedad appHighlight de la directiva esté disponible para enlace.

  3. En app.component.ts, añade una propiedad color al AppComponent.

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

    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';}
  4. Para aplicar simultáneamente la directiva y el color, usa enlace de propiedad con el selector de directiva appHighlight, estableciéndolo 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>

    El enlace de atributo [appHighlight] realiza dos tareas:

    • Aplica la directiva de resaltado al elemento <p>
    • Establece el color de resaltado de la directiva con un enlace de propiedad

Estableciendo el valor con entrada de usuario

Esta sección te guía a través de añadir botones de radio para vincular tu elección de color a la directiva appHighlight.

  1. Añade marcado a app.component.html para elegir un color de la siguiente manera:

    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>
  2. Revisa AppComponent.color para que no tenga valor inicial.

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

    import {Component} from '@angular/core';import {HighlightDirective} from './highlight.directive';@Component({  selector: 'app-root',  templateUrl: './app.component.html',  imports: [HighlightDirective],})export class AppComponent {  color = '';}
  3. En highlight.directive.ts, revisa el método onMouseEnter para que primero trate de resaltar con appHighlight y recurra a red si appHighlight es 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;  }}
  4. Ejecuta tu aplicación para verificar que el usuario puede elegir el color con los botones de radio.

    Gif animado de la directiva de resaltado refactorizada cambiando color según el botón de radio que selecciona el usuario

Enlazando a una segunda propiedad

Esta sección te guía a través de configurar tu aplicación para que el desarrollador pueda establecer el color por defecto.

  1. Añade una segunda propiedad Input() a HighlightDirective llamada 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;  }}
  2. Revisa el onMouseEnter de la directiva para que primero trate de resaltar con appHighlight, luego con defaultColor, y finalmente con red si ambas propiedades son 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;  }}
  3. Para enlazar a AppComponent.color y usar "violet" como el color por defecto, añade el siguiente HTML. En este caso, el enlace defaultColor no usa corchetes, [], porque es 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>

    Como con los componentes, puedes agreg múltiples enlaces de propiedad de directiva a un elemento host.

El color por defecto es rojo si no hay enlace de color por defecto. Cuando el usuario elige un color, el color seleccionado se convierte en el color de resaltado activo.

Gif animado de la directiva de resaltado final que muestra color rojo sin enlace y violeta con el color por defecto establecido. Cuando el usuario selecciona color, la selección toma precedencia.

Desactivando el procesamiento de Angular con NgNonBindable

Para prevenir la evaluación de expresiones en el navegador, añade ngNonBindable al elemento host. ngNonBindable desactiva la interpolación, directivas y enlace en plantillas.

En el siguiente ejemplo, la expresión {{ 1 + 1 }} se renderiza tal como está en tu editor de código, y no muestra 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 un elemento detiene el enlace para los elementos hijos de ese elemento. Sin embargo, ngNonBindable aún permite que las directivas funcionen en el elemento donde aplicas ngNonBindable. En el siguiente ejemplo, la directiva appHighlight sigue activa pero Angular no evalúa la expresión {{ 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>

Si aplicas ngNonBindable a un elemento padre, Angular desactiva la interpolación y el enlace de cualquier tipo, como enlace de propiedad o enlace de evento, para los hijos del elemento.