DEV Community

Cover image for Angular Directives
Gustavo Garsaky
Gustavo Garsaky

Posted on

Angular Directives

Una directiva es un atributo que cambia la apariencia o comportamiento de un componente. Imagina que es como un "inyector" de código CSS/JS. Una directiva es una clase decorada con @Directive, decorador que acepta un objeto. Entre las propiedades del objeto le pasamos uno escencial, el cual es selector y por medio del cual le indicamos el nombre del atributo que inyectaremos en otros componentes. Veamos cómo luce:

import { Directive } from '@angular/core'

@Directive({
  selector: '[myAwesomeAttribute]'
})
export class MyAwesomeDirective {

}
Enter fullscreen mode Exit fullscreen mode

Si quisiéramos usar ese atributo, sería en el template del componente:

<div myAwesomeAttribute></div>
Enter fullscreen mode Exit fullscreen mode

Sin embargo, la directiva por sí misma no realiza nada. Para modificar la apariencia o comportamiento de un elemento debemos hacer uso de algunas herramientas..

Cambiando la apariencia

Para inyectar clases CSS a un elemento, podemos realizarlo de dos formas:

  • Usando ElementRef
  • Usando @HostBinding

ElementRef

Nos permite acceder al elemento nativo (DOM) que es host (anfitrión) de nuestra directiva. Si, por ejemplo, el host es un elemento div, obtendremos dicho elemento del DOM. Esto se hace de la siguiente manera:

constructor(ref: ElementRef) {
  const el = ref.nativeElement as HTMLElement
  el.classList.add('my-awesome-class')
}
Enter fullscreen mode Exit fullscreen mode

El código anterior le dice a Angular: "Hey, quiero que me inyectes en el constructor, la referencia al elemento en donde esta directiva está seteada.". Una vez hecho esto, podemos tener acceso al elemento DOM por medio de la propiedad nativeElement. A partir de aquí, depende de ti lo que quieras hacer con él.

HostBinding

Por medio de esta decoración podemos "bindear" datos en el host. Por ejemplo, podemos decirle qué clases css inyectar sin necesidad de usar el feo ElementRef. Esto lo hacemos pasando como atributo del decorador, el nombre de la propiedad/atributo del elemento objetivo. Veamos como se el ejemplo anterior usando este método.

// Lo hacemos directamente como propiedad
@HostBinding('class') elementClass = 'my-awesome-class'
Enter fullscreen mode Exit fullscreen mode

Y eso es suficiente para inyectar la clase my-awesome-class en el elemento.

Cambiando el comportamiento

Vimos como @HostBinding nos permite cambiar la apariencia. Existe otro decorador llamado @HostListener que nos permite escuchar por eventos del elemento y extender su funcionalidad. Veamos un ejemplo:

import { Directive, HostListener } from '@angular/core'

@Directive({
  selector: '[myAwesomeAttribute]'
})
export class MyAwesomeDirective {
  @HostListener('click')
  onElementClick() {
    // hacer algo
  }
}
Enter fullscreen mode Exit fullscreen mode

De esta manera, logramos extender la funcionalidad del elemento objetivo. Sencillo, ¿verdad?

Estableciendo valores

Una directiva también nos permite establecer valores desde el host. Esto, se logra de la misma forma que con componentes: por medio del decorador @Input.

// como propiedad
@Input() property: string
Enter fullscreen mode Exit fullscreen mode

Y lo usaríamos de la siguiente manera:

<div myAwesomeDirective="hi"></div>
Enter fullscreen mode Exit fullscreen mode

Ejemplo

Vamos a realizar un ejemplo que incluya las tres características de las directivas que hemos visto: @HostBinding, @HostListener e @Input.

@Directive({
  selector: '[appMemoButton]'
})
export class MemoButtonDirective {
  @Input('appMemoButton') key: string
  @HostBinding('class') elementClass = 'btn btn--memo'

  @HostListener('click')
  public onClick() {
    const counter = parseInt(localStorage.getItem(this.key), 10)
    localStorage.setItem(this.key, counter + 1)
  }
}
Enter fullscreen mode Exit fullscreen mode
<button appMemoButton="registerButtonClicks">Register</button>
Enter fullscreen mode Exit fullscreen mode

El ejemplo anterior es bastante simple. La idea general es guardar en nuestro navegador la cantidad de veces que se haga click sobre un botón.

Para esto, aceptamos que cada botón pase a la directiva su propio identificador para guardarse y que no se confunda con otros botones.

@Input('appMemoButton') key: string
Enter fullscreen mode Exit fullscreen mode

Lo siguiente es añadir clases CSS que previamente hemos definido.

@HostBinding('class') elementClass = 'btn btn--memo'
Enter fullscreen mode Exit fullscreen mode

Y por último, cuando se haga click en el botón, interceptamos el evento para agregar al contador de clicks de ese botón, una unidad.

@HostListener('click')
public onClick() {
  const counter = parseInt(localStorage.getItem(this.key), 10)
  localStorage.setItem(this.key, counter + 1)
}
Enter fullscreen mode Exit fullscreen mode

Conclusiones

Las directivas pueden ser muy útiles; los usos son variados. Podemos usarlos para agregar temas, extender eventos, etc. Por ejemplo, un uso muy común es para los UI Kits, en donde se define, por medio de directivas, los tipos de botones, cajas de texto, dropdowns, etc. El uso que le das depende como siempre de ti. 😉

Top comments (2)

Collapse
 
animaoleg profile image
AnimaOleg • Edited

Muy bueno GUS ! Por fin encuentro algo decente y adecuado sobre directivas (para Angular 8)

Tu post es el único que me ha servido

Collapse
 
gugadev profile image
Gustavo Garsaky

Gracias por comentar, Anima! Me agrada que te haya servido. Se viene más material, trataré de estar más activo :)

Saludos.