AngularJS (1.x):

AngularJS introduced the concept of data binding and provided directives to manipulate the DOM based on model data. To create a for loop in AngularJS, you can use the ng-repeat directive. This directive iterates over an array and generates HTML elements for each item in the array.

In your HTML template, you define the loop using ng-repeat as follows:

<div ng-controller="MyController">
  <ul>
    <li ng-repeat="item in items">{{ item }}</li>
  </ul>
</div>

Here, ng-repeat is used to loop through the items array, and for each item in the array, it generates an li element. In your JavaScript controller (MyController in this case), you would define the items array that you want to loop through.

Angular 2+ (Angular 2, 4, 5, 6, 7, 8, 9, 10, 11, etc.):

Angular 2 and subsequent versions introduced a complete rewrite of the framework. In these versions, you can create a for loop using the *ngFor directive. This directive is part of Angular’s template syntax.

In your HTML template, you can use *ngFor as follows:

<div *ngFor="let item of items">
  {{ item }}
</div>

In your Angular component, you define the items array and bind it to the template. Here’s an example in Angular 11:

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

@Component({
  selector: 'my-app',
  template: `
    <div *ngFor="let item of items">
      {{ item }}
    </div>
  `
})
export class MyComponent {
  items: string[] = ['Item 1', 'Item 2', 'Item 3'];
}

The *ngFor directive iterates through the items array and dynamically generates HTML elements for each item.

Note that the loop variable item is only visible inside the loop, you would not be able to access it outside the *ngFor section.

Angular 2 and later versions adopted a component-based architecture and embraced modern TypeScript features, which improved code structure and maintainability. The *ngFor directive is an essential tool for handling loops in Angular applications.

Finding the index of a list element(Angular 2+):

A very common requirement is to add to a list the numeric index position of its element. We can get the index of the current element by using the index variable.

<tr *ngFor="let item of items; let i = index">
    <td>{{item}}</td>
    <td>{{i}}</td>
</tr>

Note that you need the let keyword to get the value of the index, otherwise you will get an error similar to this one:

Parser Error: Unexpected token = at column ...

How does *ngFor work when we add or remove elements from the list?

As the input list gets modified, *ngFor will try to avoid to constantly create and destroy the DOM elements of the list, as this is an expensive operation. Also, when we pass to *ngFor a new list, this does not mean that the whole list will be re-built, meaning all the DOM re-created.

Many of the existing DOM elements will be reused and only some values inside them will be overwritten, and the decision is taken for each element in the list separately.

In order to take that decision Angular needs to identify each list element in a unique way, because for example if we pass in a new list with a different order, Angular will try to identify the elements and re-order the DOM elements of the list without deleting them and recreating them.

How are list items tracked by default?

*ngFor by default tracks list items using object identity. This means that if you build a list of new objects from scratch with the exact same values as the previous list and pass this newly built list to *ngFor, Angular will not be able to tell that a given list item is already present or not.

From a point of view of object identity, the new list contains a whole new set of items, completely different from the previous set. This is the case if for example we query the data again from the backend.

Tracking by object identity is a good default strategy because Angular has no information about the object so it cannot tell which property it should use for tracking.

How to use trackBy?

We can provide our own mechanism for tracking items in a list by using trackBy. We need to pass a function to trackBy, and the function takes a couple of arguments, which are an index and the current item:

@Component({
  selector: 'my-app',
  template: `
  <ul>
    <li *ngFor="let item of items; trackBy: trackItems">
        {{item.name}}
    </li>
  </ul>
`,
})

export class App {
  items = [
    { id: 1, name: 'item1' },
    { id: 2, name: 'item2' },
    { id: 3, name: 'item3' },
  ];

  trackItems(index: number, item: any) {
    return item ? item.id : undefined;
  }
}

This implementation would do the tracking based on the id property.

When to use trackBy?

The use of trackBy it’s a performance optimization and is usually not needed by default, it’s in principle only needed if running into performance issues.

Let’s say that you are shipping to ancient mobile browsers or ancient versions of IE: you might want to consider applying trackBy as a precaution in your larger tables, but it really depends on your system and the use case.

Support On Demand!

Angular