👋 Vamos a explorar el fascinante mundo de las directivas - ¡esos pequeños hechizos que transforman vuestro HTML aburrido en interfaces interactivas y dinámicas!
🔮 Tipos de Directivas: ¡Conócelos todos!
Angular nos ofrece tres tipos mágicos de directivas (¡como si fueran las casas de Hogwarts! 😉):
- Directivas de Componentes 🏠 - ¡Son las más conocidas! Básicamente cualquier componente que creas.
@Component({
selector: 'app-magic',
template: '<p>¡Abracadabra!</p>'
})
¿Por qué se consideran directivas? ¡Porque cuando usas <app-magic>
en tu HTML, estás dando instrucciones al DOM!
- Directivas Estructurales 🧱 - Estas cambian la estructura de tu página como por arte de magia.
<!-- Sintaxis tradicional con asterisco -->
<div *ngIf="tienePermiso">¡Contenido secreto revelado!</div>
<div *ngFor="let poción of pociones">{{ poción.nombre }}</div>
<!-- Nueva sintaxis con @ (Angular 17+) -->
@if (tienePermiso) {
<div>¡Contenido secreto revelado!</div>
}
@for (poción of pociones; track poción.id) {
<div>{{ poción.nombre }}</div>
}
¡Fíjate en el asterisco *
o el nuevo @
! Son como varitas mágicas que indican que algo va a aparecer o desaparecer.
🌈 Directivas Estructurales Integradas en Angular 🌈
1. @if / *ngIf 🚦
Esta directiva es como un guardia de seguridad que decide si un elemento puede entrar a la fiesta del DOM o no.
<!-- Sintaxis tradicional -->
<div *ngIf="usuario.esPremium">¡Contenido exclusivo para ti!</div>
<!-- Sintaxis moderna -->
@if (usuario.esPremium) {
<div>¡Contenido exclusivo para ti!</div>
} @else {
<div>¡Hazte premium para ver este contenido!</div>
}
¡La nueva sintaxis @if/@else es mucho más clara que el viejo *ngIf con ng-template para el else!
2. @for / *ngFor 🔄
¡El mago duplicador! Toma un elemento y lo clona para cada item de una colección.
<!-- Sintaxis tradicional -->
<ul>
<li *ngFor="let hechizo of hechizos; let i = index; trackBy: trackByFn">
{{i+1}}. {{hechizo.nombre}}
</li>
</ul>
<!-- Sintaxis moderna -->
<ul>
@for (hechizo of hechizos; track hechizo.id; let i = $index) {
<li>{{i+1}}. {{hechizo.nombre}}</li>
} @empty {
<li>¡No conoces ningún hechizo todavía!</li>
}
</ul>
¡La nueva sintaxis @for incluye @empty para cuando la lista está vacía! ¡Y el tracking es más sencillo!
3. @switch / *ngSwitch 🔀
Como un interruptor mágico que elige entre diferentes opciones.
<!-- Sintaxis tradicional -->
<div [ngSwitch]="poción.tipo">
<div *ngSwitchCase="'curación'">Recupera 50 HP</div>
<div *ngSwitchCase="'fuerza'">+10 de ataque</div>
<div *ngSwitchDefault>Efecto desconocido</div>
</div>
<!-- Sintaxis moderna -->
@switch (poción.tipo) {
@case ('curación') {
<div>Recupera 50 HP</div>
}
@case ('fuerza') {
<div>+10 de ataque</div>
}
@default {
<div>Efecto desconocido</div>
}
}
¡La nueva sintaxis es mucho más parecida a un switch de JavaScript!
4. @defer 🚀 (¡Novedad en Angular 17!)
¡La directiva del futuro! Permite cargar contenido de forma perezosa o bajo demanda.
@defer {
<!-- Contenido pesado que se cargará después -->
<app-mapa-3d></app-mapa-3d>
} @loading {
<p>Cargando mapa...</p>
} @error {
<p>¡Ups! No se pudo cargar el mapa</p>
}
<!-- También podemos definir cuándo cargar -->
@defer (on viewport) {
<app-galería-imágenes></app-galería-imágenes>
}
@defer (on timer(5s)) {
<app-publicidad></app-publicidad>
}
¡@defer es como magia avanzada! Permite cargar componentes solo cuando son necesarios, mejorando el rendimiento.
🎨 Directivas de Atributo Integradas 🎨
1. [ngClass] 👕
¡El estilista mágico! Añade o quita clases CSS según condiciones.
<div [ngClass]="{'mago-activo': usuario.conectado, 'mago-durmiente': !usuario.conectado}">
Estado del mago
</div>
<!-- Equivalente a: -->
<div [class.mago-activo]="usuario.conectado" [class.mago-durmiente]="!usuario.conectado">
Estado del mago
</div>
2. [ngStyle] 🖌️
¡El pintor instantáneo! Aplica estilos CSS directamente.
<div [ngStyle]="{'color': hechizo.color, 'font-size.px': hechizo.poder * 5}">
{{hechizo.nombre}}
</div>
3. [ngModel] 📝
¡El escriba mágico! Crea un vínculo bidireccional entre un control de formulario y una variable.
<!-- Requiere FormsModule -->
<input [(ngModel)]="mago.nombre" placeholder="Nombre del mago">
<p>¡Saludos, {{mago.nombre}}!</p>
¡El famoso "banana in a box" [(ngModel)]! Combina ngModel y (ngModelChange) (event binding).
🔨 ¡Creemos nuestra propia directiva! 🚀
Imaginemos que queremos una directiva que haga que los elementos brillen cuando pasamos el ratón encima. ¡Vamos a crearla!
Paso 1: Invocamos al generador mágico 🧙♂️
ng generate directive directives/brillo
# O la versión corta para magos avanzados
ng g d directives/brillo
Paso 2: Preparamos nuestro hechizo ✨
@Directive({
selector: '[appBrillo]' // 👈 ¡Así lo invocaremos en nuestro HTML!
})
export class BrilloDirective {
@Input() colorBrillo = 'gold'; // 🌟 Color predeterminado
constructor(
private el: ElementRef, // 📌 Referencia al elemento
private renderer: Renderer2 // 🎮 El control remoto del DOM
) {}
@HostListener('mouseenter') // 🐭 Cuando el ratón entra...
onMouseEnter() {
this._aplicarBrillo(this.colorBrillo);
}
@HostListener('mouseleave') // 🐭 Cuando el ratón se va...
onMouseLeave() {
this._aplicarBrillo(null); // 💨 Quitamos el brillo
}
private _aplicarBrillo(color: string | null) {
// 🧙♂️ Magia pura: cambiamos el estilo sin tocar el DOM directamente
this.renderer.setStyle(
this.el.nativeElement,
'box-shadow',
color ? `0 0 10px ${color}` : null
);
this.renderer.setStyle(
this.el.nativeElement,
'transition',
'box-shadow 0.3s'
);
}
}
Paso 3: ¡A usarla! 🎉
<button appBrillo colorBrillo="purple">¡Este botón brilla en morado!</button>
<div appBrillo>¡Yo brillo en dorado (valor por defecto)!</div>
🧱 Directivas Estructurales: ¡Construyendo y demoliendo! 🏗️
Las directivas estructurales son como arquitectos del DOM. Vamos a crear una que haga lo contrario que *ngIf
(¡porque los rebeldes molan! 😎).
@Directive({
selector: '[appUnless]' // 👈 Se usará como *appUnless="condición"
})
export class UnlessDirective {
private hasView = false; // 👀 ¿Hemos creado ya la vista?
constructor(
private templateRef: TemplateRef<any>, // 📝 La plantilla a mostrar
private viewContainer: ViewContainerRef // 🧪 El contenedor donde mostrarla
) {}
@Input() set appUnless(condition: boolean) {
// 🔄 Lógica invertida respecto a *ngIf
if (!condition && !this.hasView) {
// ✅ Si la condición es falsa Y no hemos creado la vista
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
// ❌ Si la condición es cierta Y tenemos una vista
this.viewContainer.clear(); // 🧹 Limpiamos el contenedor
this.hasView = false;
}
}
}
Uso (con ambas sintaxis):
<!-- Sintaxis tradicional -->
<p *appUnless="estáLloviendo">¡Vamos a la playa! 🏖️</p>
<!-- Si implementamos soporte para la nueva sintaxis -->
@unless (estáLloviendo) {
<p>¡Vamos a la playa! 🏖️</p>
}
🎯 Reglas de Oro del Profesor de Directivas 📚
- ¡No toques el DOM directamente! 🚫
// ❌ NUNCA hagas esto:
this.el.nativeElement.style.color = 'red';
// ✅ Usa siempre el Renderer2:
this.renderer.setStyle(this.el.nativeElement, 'color', 'red');
¿Por qué? Porque Angular puede ejecutarse en plataformas donde el DOM no existe (SSR, web workers).
- Nombres con prefijos claros 📋
// ❌ Mal: selector: '[highlight]'
// ✅ Bien: selector: '[appHighlight]'
Así evitamos colisiones con otras bibliotecas o directivas nativas.
- Una directiva = Una responsabilidad 🎯
// ❌ Mal: Una directiva que cambia color Y añade animación Y modifica texto
// ✅ Bien: Directivas separadas para cada función
¡Divide y vencerás! Las directivas pequeñas son más reutilizables.
- Documenta tus creaciones mágicas 📝
/**
* Aplica un efecto de brillo cuando el usuario pasa el ratón sobre el elemento.
* @param colorBrillo - Color del efecto (por defecto: gold)
* @example <div appBrillo colorBrillo="blue">Contenido</div>
*/
Tus compañeros (y tu yo del futuro) te lo agradecerán.
- Prueba tus hechizos antes de lanzarlos 🧪
describe('BrilloDirective', () => {
// Configuración de pruebas...
it('debe añadir brillo al pasar el ratón', () => {
triggerEventHandler('mouseenter', {});
expect(element.style.boxShadow).toContain('gold');
});
});
¡Un mago responsable siempre prueba sus hechizos!
🎓 ¡Tarea para casa! 📝
Ahora que ya sois aprendices de magos de las directivas, os propongo este desafío:
- Crea una directiva
appCuentaClics
que cuente cuántas veces se ha hecho clic en un elemento. - Debe mostrar un pequeño contador en la esquina superior derecha.
- Bonus: Añade un método para reiniciar el contador.
¡Recordad compartir vuestros hechizos en la próxima clase! 🧙♂️✨
¿Preguntas? ¡Levantad vuestra mano mágica! 🪄
Top comments (0)