En esta página
Templates y control flow nativo
Control flow nativo en Angular
Angular 21 usa bloques de control flow nativos directamente en los templates. Esta sintaxis reemplaza las directivas estructurales *ngIf, *ngFor y *ngSwitch de versiones anteriores.
@if / @else
Renderiza contenido condicionalmente:
@if (usuario()) {
<p>Bienvenido, {{ usuario()!.nombre }}</p>
} @else if (cargando()) {
<p>Cargando...</p>
} @else {
<p>Inicia sesión para continuar</p>
}A diferencia de *ngIf, no necesitas importar ninguna directiva. El bloque @else if es nativo y no requiere ng-template.
@for / @empty
Itera sobre colecciones. La expresión track es obligatoria y debe referenciar una propiedad única:
@for (item of items(); track item.id) {
<div>{{ item.nombre }}</div>
} @empty {
<div>No hay elementos para mostrar.</div>
}El bloque @empty se renderiza cuando la colección esta vacia. Variables contextuales disponibles:
| Variable | Tipo | Descripcion |
|---|---|---|
$index |
number |
Índice del elemento actual |
$first |
boolean |
Es el primer elemento |
$last |
boolean |
Es el último elemento |
$even |
boolean |
Índice par |
$odd |
boolean |
Índice impar |
$count |
number |
Total de elementos |
Ejemplo con variables contextuales:
@for (paso of pasos(); track paso.id; let i = $index) {
<div [class.activo]="i === pasoActual()">
Paso {{ i + 1 }}: {{ paso.título }}
</div>
}@switch
Evalua una expresión y renderiza el caso correspondiente:
@switch (estado()) {
@case ('activo') {
<span class="badge verde">Activo</span>
}
@case ('pendiente') {
<span class="badge amarillo">Pendiente</span>
}
@default {
<span class="badge gris">Desconocido</span>
}
}Interpolacion y bindings
Ademas del control flow, los templates Angular usan:
- Interpolacion:
{{ expresión }}para mostrar valores - Property binding:
[propiedad]="expresión"para enlazar propiedades del DOM - Event binding:
(evento)="handler()"para escuchar eventos - Two-way binding:
[(ngModel)]="signal"para formularios (requiere FormsModule)
<!-- Property binding -->
<img [src]="avatar()" [alt]="nombre()" />
<!-- Class binding condicional -->
<div [class.activo]="estaActivo()">Contenido</div>
<!-- Style binding -->
<div [style.color]="estaActivo() ? 'green' : 'gray'">Estado</div>Pipes en templates
Los pipes transforman valores para la vista:
<p>{{ precio() | currency:'USD' }}</p>
<p>{{ fecha() | date:'longDate' }}</p>
<p>{{ nombre() | uppercase }}</p>Práctica
- Renderiza una lista con @for: Crea un array de al menos 5 objetos (por ejemplo, tareas) y renderizalos con
@forusandotrackporid. Agrega un bloque@emptyque muestre un mensaje cuando la lista este vacia. - Agrega filtros con @if y @switch: Implementa botones de filtro que muestren u oculten elementos usando
@if. Usa@switchpara mostrar un badge diferente segun una propiedad del objeto (por ejemplo, prioridad o categoria).
En la siguiente leccion profundizaremos en Signals, la primitiva reactiva central de Angular 21.
import { Component, signal, computed, ChangeDetectionStrategy } from '@angular/core';
interface Producto {
id: number;
nombre: string;
precio: number;
categoria: 'electronica' | 'ropa' | 'hogar';
disponible: boolean;
}
@Component({
selector: 'app-catálogo',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './catálogo.html',
})
export class Catalogo {
readonly productos = signal<Producto[]>([
{ id: 1, nombre: 'Laptop Pro', precio: 1200, categoria: 'electronica', disponible: true },
{ id: 2, nombre: 'Camiseta Angular', precio: 25, categoria: 'ropa', disponible: true },
{ id: 3, nombre: 'Lampara LED', precio: 45, categoria: 'hogar', disponible: false },
{ id: 4, nombre: 'Teclado mecanico', precio: 89, categoria: 'electronica', disponible: true },
]);
readonly filtro = signal<string>('todos');
readonly productosFiltrados = computed(() => {
const f = this.filtro();
if (f === 'todos') return this.productos();
return this.productos().filter(p => p.categoria === f);
});
readonly total = computed(
() => this.productosFiltrados().reduce((sum, p) => sum + p.precio, 0)
);
cambiarFiltro(categoria: string): void {
this.filtro.set(categoria);
}
}
Inicia sesión para guardar tu progreso