← Back to all tutorials

ngFor

Deep dive into *ngFor — loop through arrays, access index and other variables, trackBy for performance.

ngFor

*ngFor repeats a template for each item in an array or iterable. It's the Angular equivalent of a for loop in the template.

Basic Syntax

<ul>
    <li *ngFor="let fruit of fruits">{{ fruit }}</li>
</ul>

// component
fruits = ['Apple', 'Banana', 'Cherry', 'Date'];

Accessing the Index

<ul>
    <li *ngFor="let item of items; let i = index">
        {{ i + 1 }}. {{ item }}
    </li>
</ul>

All Available Variables

VariableTypeDescription
indexnumberIndex of the current item (0-based)
firstbooleanTrue if this is the first item
lastbooleanTrue if this is the last item
evenbooleanTrue if index is even
oddbooleanTrue if index is odd
<div *ngFor="let user of users; 
             let i = index; 
             let isFirst = first; 
             let isLast = last; 
             let isEven = even">
    <div class="user-row" 
         [class.first-row]="isFirst"
         [class.last-row]="isLast"
         [class.even-row]="isEven">
        {{ i + 1 }}. {{ user.name }}
    </div>
</div>

Looping Through Objects

// component
users = [
    { id: 1, name: 'Alice', role: 'Admin' },
    { id: 2, name: 'Bob', role: 'Developer' },
    { id: 3, name: 'Carol', role: 'Designer' },
];

// template
<div class="card" *ngFor="let user of users">
    <h3>{{ user.name }}</h3>
    <p>Role: {{ user.role }}</p>
    <a [routerLink]="['/users', user.id]">View Profile</a>
</div>

Nested *ngFor

// component
categories = [
    { name: 'Frontend', skills: ['HTML', 'CSS', 'JavaScript'] },
    { name: 'Backend', skills: ['Node.js', 'Python', 'SQL'] },
];

// template
<div *ngFor="let category of categories">
    <h3>{{ category.name }}</h3>
    <ul>
        <li *ngFor="let skill of category.skills">{{ skill }}</li>
    </ul>
</div>

trackBy — Performance Optimization

<!-- Without trackBy, Angular re-renders ALL items when the array changes -->
<div *ngFor="let user of users; trackBy: trackByUserId">
    {{ user.name }}
</div>

// component
trackByUserId(index: number, user: any): number {
    return user.id;  // Use unique id for tracking
}

trackBy tells Angular how to identify each item. Instead of destroying and recreating all DOM elements, it only updates what actually changed. Essential for large lists.

Combining *ngFor with *ngIf

<!-- Can't put both on the same element! Use ng-container: -->
<ng-container *ngFor="let user of users">
    <div class="user-card" *ngIf="user.isActive">
        {{ user.name }}
    </div>
</ng-container>

<ng-container> is an Angular grouping element that doesn't render in the DOM — perfect for combining structural directives.

Key Takeaways

  • *ngFor="let item of items" loops through arrays
  • Access index, first, last, even, odd local variables
  • Use trackBy for performance with large or frequently-changing lists
  • Use <ng-container> to combine *ngFor with *ngIf on the same level
  • Nested *ngFor works for hierarchical data