Directivas Personalizadas
Las Directivas Personalizadas en Angular son una de las herramientas más poderosas del framework, ya que permiten extender el comportamiento de los elementos HTML existentes o crear nuevos patrones reutilizables que enriquecen la interacción entre componentes. A diferencia de los componentes, las directivas no generan una nueva plantilla, sino que manipulan el DOM o añaden lógica dinámica a los elementos que ya existen en una vista.
El uso de directivas personalizadas es esencial cuando se desea aplicar comportamientos específicos a múltiples elementos sin duplicar código, favoreciendo así la reutilización, la cohesión del sistema y la separación de responsabilidades. Las directivas pueden utilizarse para modificar estilos, escuchar eventos, controlar visibilidad o crear validaciones personalizadas, integrándose de manera fluida dentro del flujo de datos (data flow) y el ciclo de vida (lifecycle) de Angular.
A lo largo de este tutorial aprenderás a crear, estructurar y optimizar directivas personalizadas en proyectos Angular modernos. También entenderás cómo se relacionan con los componentes, cómo evitar errores comunes como el prop drilling o las mutaciones de estado, y cómo integrarlas en el contexto de Single Page Applications (SPAs) con arquitecturas reactivas y escalables.
Ejemplo Básico
typescript// directiva simple para cambiar el color de fondo al pasar el mouse
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
@Directive({
selector: '[appHoverColor]'
})
export class HoverColorDirective {
@Input() appHoverColor: string = 'yellow';
constructor(private el: ElementRef) {}
@HostListener('mouseenter') onMouseEnter() {
this.highlight(this.appHoverColor);
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight('');
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
// componente que utiliza la directiva
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: ` <h2 appHoverColor="lightblue">Pasa el mouse por encima de este texto</h2> <p appHoverColor="lightgreen">Las directivas personalizadas son poderosas en Angular.</p>
`
})
export class AppComponent {}
En este ejemplo, la directiva HoverColorDirective demuestra cómo manipular directamente el DOM en Angular usando una lógica encapsulada y reutilizable. La clase está decorada con @Directive
, que define su selector —en este caso, un atributo [appHoverColor]
. El decorador @Input
permite que el color se configure desde el componente, lo que mantiene un flujo de datos unidireccional limpio y predecible.
El ElementRef
proporciona una referencia nativa al elemento HTML, permitiendo aplicar modificaciones seguras al DOM. Los decoradores @HostListener
capturan eventos del host (como mouseenter
y mouseleave
) y ejecutan métodos asociados. Así se logra un comportamiento interactivo sin necesidad de duplicar lógica o manipular directamente el DOM en múltiples componentes.
Este patrón respeta el ciclo de vida de Angular al aislar responsabilidades: el componente mantiene el control de datos, mientras la directiva administra el comportamiento visual. De esta manera, se evita el prop drilling y se reduce la complejidad del código. En aplicaciones grandes, este enfoque promueve la escalabilidad, ya que las directivas pueden aplicarse en distintas partes del proyecto sin alterar la lógica principal.
Ejemplo Práctico
typescript// Directiva avanzada que controla permisos de visualización basada en roles
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[appRoleAccess]'
})
export class RoleAccessDirective {
@Input() set appRoleAccess(roles: string[]) {
const userRole = this.getUserRole();
if (roles.includes(userRole)) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef
) {}
private getUserRole(): string {
// simulación de obtención de rol del usuario actual
return 'admin';
}
}
// Componente que usa la directiva
import { Component } from '@angular/core';
@Component({
selector: 'app-dashboard',
template: ` <div *appRoleAccess="['admin', 'superuser']"> <h3>Panel de Administración</h3> <p>Solo usuarios con rol adecuado pueden ver este contenido.</p> </div> <div *appRoleAccess="['user']"> <h3>Bienvenido usuario estándar</h3> </div>
`
})
export class DashboardComponent {}
Las Directivas Estructurales Personalizadas como appRoleAccess
permiten manipular la estructura del DOM dinámicamente, mostrando u ocultando elementos basados en condiciones complejas. En este caso, la directiva determina si el usuario actual tiene acceso según un rol simulado. Se inyectan TemplateRef
y ViewContainerRef
para controlar la inserción y eliminación de vistas dentro del árbol del DOM virtual de Angular.
El flujo de datos permanece unidireccional, evitando inconsistencias de estado y reduciendo el acoplamiento entre componentes. Al usar un método centralizado (getUserRole()
), la directiva puede integrarse con servicios reales de autenticación o autorización, demostrando un patrón escalable para SPAs modernas.
Este ejemplo destaca el control granular sobre la presentación sin necesidad de lógica condicional en las plantillas de componentes. También muestra cómo aprovechar los ciclos de vida del renderizado y mantener la integridad del estado global sin mutaciones directas. Con este enfoque, las aplicaciones Angular pueden optimizar rendimiento y mantener un código mantenible y seguro.
Las mejores prácticas de Angular para Directivas Personalizadas se centran en mantener un diseño desacoplado y eficiente. Cada directiva debe cumplir una única responsabilidad, alineada con los principios SOLID. Se recomienda inyectar dependencias mediante el constructor, usar @Input
para personalizar comportamiento y evitar manipular el DOM directamente fuera del contexto seguro de Angular.
Los errores comunes incluyen el prop drilling (pasar propiedades innecesarias entre componentes), las mutaciones de estado que rompen la detección de cambios y los renderizados redundantes que afectan el rendimiento. Para depurar, es recomendable usar ngDevMode
o herramientas como Augury, que permiten visualizar la jerarquía de componentes y directivas activas.
En cuanto al rendimiento, se debe minimizar el acceso al DOM, preferir Renderer2
sobre ElementRef
para operaciones críticas y limpiar las suscripciones a eventos en ngOnDestroy
. En aplicaciones seguras, se deben evitar inyecciones de código dinámico o uso directo de innerHTML
. Siguiendo estos principios, las directivas personalizadas se convierten en bloques de construcción robustos y eficientes dentro de una arquitectura Angular moderna.
📊 Tabla de Referencia
Angular Element/Concept | Description | Usage Example |
---|---|---|
@Directive | Define una clase como directiva personalizada | @Directive({ selector: '[appHighlight]' }) |
@HostListener | Escucha eventos del elemento anfitrión | @HostListener('click') onClick() { ... } |
@Input | Permite recibir valores desde un componente padre | @Input() color: string; |
TemplateRef | Referencia a la plantilla usada en directivas estructurales | constructor(private tpl: TemplateRef<any>) {} |
ViewContainerRef | Permite insertar o remover vistas dinámicamente | this.viewContainer.createEmbeddedView(this.tpl); |
Renderer2 | Acceso seguro y optimizado al DOM | this.renderer.setStyle(el.nativeElement, 'color', 'blue'); |
En resumen, las Directivas Personalizadas son un pilar fundamental para desarrollar interfaces ricas, dinámicas y altamente reutilizables en Angular. Permiten extender el comportamiento de los elementos sin necesidad de crear nuevos componentes, manteniendo un flujo de datos limpio y predecible.
Dominar las directivas implica comprender profundamente el ciclo de vida del framework, la gestión del estado y la optimización del rendimiento. Como próximos pasos, se recomienda profundizar en temas como Inyección de Dependencias, Directivas Estructurales Avanzadas y Change Detection Strategy.
En la práctica, aplicar directivas personalizadas facilita la creación de bibliotecas de componentes reutilizables, mejora la escalabilidad de SPAs y refuerza la mantenibilidad del código. Recursos adicionales recomendados incluyen la documentación oficial de Angular, ejemplos de GitHub y guías de arquitectura avanzada.
🧠 Pon a Prueba tu Conocimiento
Pon a Prueba tu Conocimiento
Ponte a prueba con este cuestionario interactivo y descubre qué tan bien entiendes el tema
📝 Instrucciones
- Lee cada pregunta cuidadosamente
- Selecciona la mejor respuesta para cada pregunta
- Puedes repetir el quiz tantas veces como quieras
- Tu progreso se mostrará en la parte superior