Angular 18: Nueva Sintaxis de Control Flow que Cambia Todo

1 de enero de 2026
Osman Jimenez
Angular Frontend TypeScript

Angular 18: La Revolución del Control Flow

Angular 18 introduce una nueva sintaxis de control flow que reemplaza las directivas estructurales tradicionales (*ngIf, *ngFor, *ngSwitch) con una sintaxis más intuitiva, performante y fácil de leer. Este cambio marca un antes y un después en cómo escribimos templates en Angular.

Adiós a las Directivas Estructurales

La nueva sintaxis elimina la confusión de las directivas estructurales y ofrece una experiencia más similar a otros frameworks modernos:

Antes (Angular 17 y anteriores)

<!-- Condicionales -->
<div *ngIf="user; else noUser">
  <h2>Bienvenido {{ user.name }}</h2>
</div>
<ng-template #noUser>
  <p>Por favor, inicia sesión</p>
</ng-template>

<!-- Bucles -->
<div *ngFor="let item of items; trackBy: trackByFn; let i = index">
  {{ i }}: {{ item.name }}
</div>

<!-- Switch -->
<div [ngSwitch]="status">
  <p *ngSwitchCase="'loading'">Cargando...</p>
  <p *ngSwitchCase="'error'">Error al cargar</p>
  <p *ngSwitchDefault>Contenido cargado</p>
</div>

Ahora (Angular 18+)

<!-- Condicionales -->
@if (user) {
  <h2>Bienvenido {{ user.name }}</h2>
} @else {
  <p>Por favor, inicia sesión</p>
}

<!-- Bucles -->
@for (item of items; track item.id; let i = $index) {
  <div>{{ i }}: {{ item.name }}</div>
} @empty {
  <p>No hay elementos para mostrar</p>
}

<!-- Switch -->
@switch (status) {
  @case ('loading') {
    <p>Cargando...</p>
  }
  @case ('error') {
    <p>Error al cargar</p>
  }
  @default {
    <p>Contenido cargado</p>
  }
}

Ventajas de la Nueva Sintaxis

  1. Legibilidad mejorada: Código más claro y fácil de entender
  2. Mejor rendimiento: Optimizaciones internas del compilador
  3. Type safety: Mejor inferencia de tipos en templates
  4. Debugging: Stack traces más claros
  5. Menos boilerplate: No más ng-template para casos simples

Ejemplos Avanzados

Condicionales Anidados

@if (user) {
  @if (user.isAdmin) {
    <admin-panel />
  } @else if (user.isModerator) {
    <moderator-panel />
  } @else {
    <user-panel />
  }
} @else {
  <login-form />
}

Bucles con Condiciones

@for (product of products; track product.id) {
  @if (product.inStock) {
    <div class="product-card">
      <h3>{{ product.name }}</h3>
      <p>Precio: {{ product.price | currency }}</p>
      
      @if (product.discount > 0) {
        <span class="discount">-{{ product.discount }}%</span>
      }
      
      @switch (product.category) {
        @case ('electronics') {
          <icon name="laptop" />
        }
        @case ('clothing') {
          <icon name="shirt" />
        }
        @default {
          <icon name="package" />
        }
      }
    </div>
  }
} @empty {
  <div class="empty-state">
    <p>No hay productos disponibles</p>
    <button (click)="loadProducts()">Recargar</button>
  </div>
}

Variables de Template Mejoradas

@for (user of users; track user.id; let isFirst = $first, isLast = $last, idx = $index) {
  <div class="user-item" 
       [class.first]="isFirst" 
       [class.last]="isLast">
    <span class="index">{{ idx + 1 }}</span>
    <span class="name">{{ user.name }}</span>
    
    @if (isFirst) {
      <badge text="Primer usuario" />
    }
  </div>
}

Migración Automática

Angular CLI incluye un schematic para migrar automáticamente:

# Migrar todo el proyecto
ng generate @angular/core:control-flow

# Migrar archivos específicos
ng generate @angular/core:control-flow --path src/app/components

Ejemplo de Migración

// Antes
<div *ngIf="loading; else content">
  <spinner />
</div>
<ng-template #content>
  <div *ngFor="let item of items; trackBy: trackByFn">
    {{ item.name }}
  </div>
</ng-template>

// Después (automático)
@if (loading) {
  <spinner />
} @else {
  @for (item of items; track trackByFn($index, item)) {
    <div>{{ item.name }}</div>
  }
}

Optimizaciones de Rendimiento

Track Functions Mejoradas

// Función de tracking personalizada
trackByUserId(index: number, user: User): number {
  return user.id;
}

// Uso en template
@for (user of users; track trackByUserId($index, user)) {
  <user-card [user]="user" />
}

// O directamente con la propiedad
@for (user of users; track user.id) {
  <user-card [user]="user" />
}

Lazy Loading Condicional

@if (showAdvancedFeatures) {
  @defer (on viewport) {
    <advanced-component />
  } @placeholder {
    <div class="placeholder">Cargando funciones avanzadas...</div>
  } @loading (minimum 500ms) {
    <spinner />
  } @error {
    <p>Error al cargar el componente</p>
  }
}

Integración con Signals

@Component({
  template: `
    @if (userSignal()) {
      <h2>Bienvenido {{ userSignal()!.name }}</h2>
      
      @for (notification of notificationsSignal(); track notification.id) {
        <div class="notification" [class.unread]="!notification.read">
          {{ notification.message }}
        </div>
      } @empty {
        <p>No tienes notificaciones</p>
      }
    } @else {
      <login-form (login)="handleLogin($event)" />
    }
  `
})
export class DashboardComponent {
  userSignal = signal<User | null>(null);
  notificationsSignal = signal<Notification[]>([]);
  
  handleLogin(user: User) {
    this.userSignal.set(user);
    this.loadNotifications();
  }
}

Mejores Prácticas

  1. Usa track functions: Siempre especifica track en @for para mejor rendimiento
  2. Aprovecha @empty: Maneja estados vacíos de forma elegante
  3. Combina con @defer: Para lazy loading inteligente
  4. Mantén la lógica simple: Evita expresiones complejas en templates
  5. Usa type guards: Para mejor type safety en condicionales

Compatibilidad y Adopción

  • Retrocompatibilidad: Las directivas antiguas siguen funcionando
  • Migración gradual: Puedes migrar archivo por archivo
  • Herramientas: Soporte completo en Angular Language Service
  • Comunidad: Adopción rápida por parte de la comunidad

Conclusión

La nueva sintaxis de control flow en Angular 18 representa una evolución natural del framework hacia una experiencia de desarrollo más moderna y eficiente. Con mejor rendimiento, mayor legibilidad y herramientas de migración automática, no hay razón para no adoptar esta nueva sintaxis en tus proyectos.

Esta mejora, combinada con Signals y Standalone Components, posiciona a Angular como uno de los frameworks más modernos y eficientes del ecosistema frontend.

¿Ya has migrado tus proyectos a la nueva sintaxis? ¿Qué te parece esta evolución de Angular?