Compartir en Twitter
Go to Homepage

DIRECTIVAS ESTRUCTURALES *NGFOR Y *NGIF EN ANGULAR EXPLICADAS

January 8, 2026

Introducción a las Directivas Estructurales en Angular

Las directivas estructurales representan uno de los pilares fundamentales en el desarrollo de aplicaciones con Angular. Estas directivas permiten modificar la estructura del DOM de manera dinámica, agregando, eliminando o reemplazando elementos según las condiciones del código. Entre las más utilizadas se encuentran *ngFor y *ngIf, que facilitan la iteración sobre colecciones de datos y el renderizado condicional de contenido. Aunque en versiones recientes de Angular se han introducido nuevas sintaxis de control de flujo integradas, las directivas clásicas siguen siendo ampliamente compatibles y empleadas en proyectos existentes.

El uso adecuado de estas directivas contribuye a mantener el código limpio, legible y eficiente. En este tutorial exploraremos en detalle su funcionamiento, con ejemplos prácticos que ilustran su aplicación en escenarios reales de desarrollo frontend.

Entendiendo la Directiva *ngFor

La directiva *ngFor permite recorrer una colección iterable, como un array, y generar instancias de una plantilla para cada elemento. Esta funcionalidad resulta esencial cuando se necesita mostrar listas dinámicas de datos obtenidos de servicios o definidos en el componente.

Para comenzar, consideremos un componente básico que contiene un array de objetos representando información de personas.

import { Component } from "@angular/core";

@Component({
    selector: "app-ejemplo",
    templateUrl: "./ejemplo.component.html",
    standalone: true,
})
export class EjemploComponent {
    amigos = [
        { nombre: "Nishant", edad: 25 },
        { nombre: "Shailesh", edad: 45 },
        { nombre: "Abhishek", edad: 36 },
        { nombre: "Akshay", edad: 65 },
        { nombre: "Ashish", edad: 12 },
        { nombre: "Uday", edad: 31 },
        { nombre: "Mayank", edad: 45 },
        { nombre: "Raju", edad: 74 },
    ];
}

En la plantilla HTML asociada, aplicamos *ngFor sobre un elemento dentro de una lista no ordenada.

<ul>
    <li *ngFor="let persona of amigos">
        {{ persona.nombre }} tiene {{ persona.edad }} años
    </li>
</ul>

Aquí, la sintaxis let persona of amigos crea una variable local persona que representa cada ítem del array en cada iteración. El uso de interpolación {{ }} permite mostrar las propiedades del objeto. Este enfoque genera automáticamente un elemento por cada entrada en el array, resultando en una lista dinámica.

Una variante común consiste en personalizar el formato de presentación. Por ejemplo, podemos ajustar el texto para mayor claridad.

<ul>
    <li *ngFor="let persona of amigos">
        El nombre es {{ persona.nombre }} y su edad es {{ persona.edad }}
    </li>
</ul>

Esta flexibilidad permite adaptar la visualización a requisitos específicos del diseño. Además, *ngFor expone variables locales adicionales que enriquecen el control durante la iteración, como index, first, last, even y odd.

Por ejemplo, para numerar los elementos de la lista:

<ul>
    <li *ngFor="let persona of amigos; let i = index">
        {{ i + 1 }}. {{ persona.nombre }} tiene {{ persona.edad }} años
    </li>
</ul>

La variable i captura el índice del elemento actual, comenzando desde cero. Esta característica resulta particularmente útil en tablas o listas ordenadas donde se requiere identificar la posición.

Otra variable valiosa es even, que indica si el índice es par.

<ul>
    <li
        *ngFor="let persona of amigos; let par = even"
        [style.background-color]="par ? 'lightgray' : 'white'"
    >
        {{ persona.nombre }} tiene {{ persona.edad }} años
    </li>
</ul>

En este caso, aplicamos un estilo condicional para alternar el color de fondo, mejorando la legibilidad visual de listas extensas.

La directiva *ngFor también soporta la función trackBy, que optimiza el rendimiento al identificar elementos únicos durante las actualizaciones del array. Esto evita recrear innecesariamente nodos DOM cuando solo cambian referencias.

En el componente TypeScript:

trackById(index: number, persona: any): any {
  return persona.nombre; // O un ID único si existe
}

Y en la plantilla:

<ul>
    <li *ngFor="let persona of amigos; trackBy: trackById">
        {{ persona.nombre }} tiene {{ persona.edad }} años
    </li>
</ul>

Esta práctica es recomendada en listas grandes o cuando los datos se actualizan frecuentemente, ya que reduce significativamente las operaciones en el DOM.

Explorando la Directiva *ngIf

La directiva *ngIf evalúa una expresión booleana y renderiza o elimina el elemento asociado según su valor. Esta capacidad resulta indispensable para controlar la visibilidad de secciones del interfaz basadas en estados de la aplicación, como autenticación, carga de datos o validaciones.

Partiendo del ejemplo anterior con la lista de amigos, agreguemos un mecanismo para ocultar o mostrar la lista mediante un botón.

Primero, definimos una propiedad booleana en el componente.

import { Component } from "@angular/core";

@Component({
    selector: "app-ejemplo",
    templateUrl: "./ejemplo.component.html",
    standalone: true,
})
export class EjemploComponent {
    amigos = [
        /* ... mismo array anterior ... */
    ];
    visible: boolean = true;

    toggleVisibilidad() {
        this.visible = !this.visible;
    }
}

En la plantilla, envolvemos la lista con *ngIf.

<ul *ngIf="visible">
    <li *ngFor="let persona of amigos">
        {{ persona.nombre }} tiene {{ persona.edad }} años
    </li>
</ul>

<button (click)="toggleVisibilidad()">
    {{ visible ? 'Ocultar lista' : 'Mostrar lista' }}
</button>

Cuando visible es true, la lista se renderiza; de lo contrario, se elimina completamente del DOM. Esto difiere de ocultar con CSS, ya que *ngIf evita cargar recursos innecesarios.

*ngIf también soporta cláusulas else y then para mayor expresividad.

<div *ngIf="visible; else bloqueElse">
    <ul>
        <li *ngFor="let persona of amigos">
            {{ persona.nombre }} tiene {{ persona.edad }} años
        </li>
    </ul>
</div>

<ng-template #bloqueElse>
    <p>La lista está oculta en este momento.</p>
</ng-template>

<button (click)="toggleVisibilidad()">
    {{ visible ? 'Ocultar lista' : 'Mostrar lista' }}
</button>

Aquí, cuando la condición es falsa, se muestra el contenido del ng-template referenciado por #bloqueElse.

Un escenario común involucra la carga asíncrona de datos. Supongamos que obtenemos la lista desde un servicio.

cargando: boolean = true;
amigos: any[] = [];

ngOnInit() {
  this.servicio.obtenerAmigos().subscribe(data => {
    this.amigos = data;
    this.cargando = false;
  });
}

En la plantilla:

<div *ngIf="!cargando; else bloqueCargando">
  <ul>
    <li *ngFor="let persona of amigos">
      {{ persona.nombre }} tiene {{ persona.edad }} años
    </li>
  </ul>
</div>

<ng-template #bloqueCargando">
  <p>Cargando datos, por favor espere...</p>
</ng-template>

Este patrón mejora la experiencia de usuario al proporcionar retroalimentación durante operaciones asíncronas.

Combinando *ngFor y *ngIf en Escenarios Complejos

En aplicaciones reales, frecuentemente se combinan ambas directivas para filtrar y mostrar datos selectivamente. Por ejemplo, mostrar solo personas mayores de edad.

<ul>
    <li *ngFor="let persona of amigos">
        <ng-container *ngIf="persona.edad >= 18; else menorEdad">
            {{ persona.nombre }} tiene {{ persona.edad }} años (adulto)
        </ng-container>
        <ng-template #menorEdad>
            {{ persona.nombre }} tiene {{ persona.edad }} años (menor)
        </ng-template>
    </li>
</ul>

El uso de evita agregar elementos extra al DOM, manteniendo una estructura limpia. Esta técnica es especialmente valiosa cuando se aplican múltiples directivas estructurales en el mismo nivel.

Otro ejemplo práctico involucra filtrado dinámico. Agreguemos un campo de búsqueda.

terminoBusqueda: string = '';

get amigosFiltrados() {
  return this.amigos.filter(p =>
    p.nombre.toLowerCase().includes(this.termoBusqueda.toLowerCase())
  );
}
<input [(ngModel)]="terminoBusqueda" placeholder="Buscar por nombre">

<ul *ngIf="amigosFiltrados.length > 0; else sinResultados">
  <li *ngFor="let persona of amigosFiltrados">
    {{ persona.nombre }} tiene {{ persona.edad }} años
  </li>
</ul>

<ng-template #sinResultados">
  <p>No se encontraron resultados para la búsqueda actual.</p>
</ng-template>

Esta combinación demuestra cómo las directivas estructurales potencian la interactividad y el manejo eficiente de datos en interfaces modernas.

Mejores Prácticas y Consideraciones de Rendimiento

Al trabajar con *ngFor en colecciones extensas, siempre implemente trackBy para minimizar reconcialiciones del DOM. Sin esta optimización, Angular recrea elementos completos ante cualquier cambio, impactando negativamente el rendimiento.

En cuanto a *ngIf, prefiera su uso sobre estilos de visibilidad cuando el contenido condicional implique recursos pesados, ya que elimina completamente los nodos del DOM.

Evite aplicar múltiples directivas estructurales directamente en el mismo elemento host. Utilice para agrupar lógicas complejas sin introducir wrappers innecesarios.

Aunque versiones actuales de Angular mantienen soporte completo para estas directivas, es importante notar que el equipo de desarrollo ha introducido nuevas construcciones de control de flujo que ofrecen ventajas adicionales en legibilidad y rendimiento. Sin embargo, *ngFor y *ngIf permanecen como opciones sólidas y ampliamente utilizadas en la comunidad.

Conclusiones

Las directivas *ngFor y *ngIf constituyen herramientas esenciales para cualquier desarrollador Angular, permitiendo crear interfaces dinámicas, responsivas y mantenibles. Su dominio facilita la implementación de listas iterativas, renderizado condicional y combinaciones avanzadas que responden a estados cambiantes de la aplicación.

A través de los ejemplos presentados, hemos visto cómo estas directivas simplifican tareas comunes en el desarrollo frontend, desde la visualización básica de datos hasta escenarios más elaborados con filtrado y carga asíncrona. La incorporación de variables locales, trackBy y ng-container eleva la calidad del código producido.

Dominar estos conceptos no solo mejora la eficiencia del desarrollo, sino que también contribuye a aplicaciones más performantes y con mejor experiencia de usuario. Continúe experimentando con variaciones y combinaciones para consolidar su comprensión práctica de estas poderosas herramientas en el ecosistema Angular.