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 {
}
Si quisiéramos usar ese atributo, sería en el template del componente:
<div myAwesomeAttribute></div>
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')
}
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'
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
}
}
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
Y lo usaríamos de la siguiente manera:
<div myAwesomeDirective="hi"></div>
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)
}
}
<button appMemoButton="registerButtonClicks">Register</button>
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
Lo siguiente es añadir clases CSS que previamente hemos definido.
@HostBinding('class') elementClass = 'btn btn--memo'
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)
}
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)
Muy bueno GUS ! Por fin encuentro algo decente y adecuado sobre directivas (para Angular 8)
Tu post es el único que me ha servido
Gracias por comentar, Anima! Me agrada que te haya servido. Se viene más material, trataré de estar más activo :)
Saludos.