Angular
Fundamentals of Angular Directives - Structural Directives

NgFor Built-in Structural Directive

PRO
Outline

NgFor

Angular makes it easy to iterate (or loop) over a collection using the NgForOf structural directive. Angular provides:

  1. A familiar for...of syntax
  2. The current index
  3. The ability to provide a custom tracking function

Let's break these down.

For...of Syntax

The for...of syntax is very similar to the ECMAScript 6 syntax for iterating over an array. For example, suppose we have an array of letters that we wish to write to the document:

for (let char of letters) {
  document.write(char);
}

Angular's syntax is similar:

<span *ngFor="let char of letters">
  {{ char }}
</span>

In the example above we are creating three <span> elements, each with the string value of the individual char in the array of letters.

For clarity, here is what the array of letters might be defined as in the directive's class:

export AppComponent {
  letters = ['a', 'b', 'c'];
}

Note that we are using string interpolation, which is just a fancy way of saying "outputting", in order to output each char string value.

Accessing the Current Index

We can also access the current index, beginning at 0 of the iteration. We'll simply declare a template input variable, which is a variable that can be referenced within a single instance of the template, and is unique to each instance of the template. We'll set the value of the template input variable equal to the index.

Here is an example of accessing the current index when using the NgFor structural directive in Angular:

<span *ngFor="let char of letters; let i = index">
  {{ i }}: {{ char }}
</span>

Note that in the example above we are outputting the index for each char within the array of letters.

The trackBy Function

Finally, Angular enables you to specify a special function that tracks the difference between each iteration in our iterable. By default Angular uses a differ() function to determine when something has changed in our collection that we are iterating over. When change is detected, Angular will re-render that individual item, or perhaps even, re-render the entire collection. While Angular is certainly optimized for performance, sometimes we know better when change has occured.

For example, let's say we have an array of people defined in our directive's class:

export class AppComponent {
  people = [
      {
          id: 1,
            name: 'Brian',
          department: 'Engineering'
        },
        {
          id: 1,
            name: 'Joe',
          department: 'Testing'
        },
        {
          id: 1,
            name: 'Lukas',
          department: 'Marketing'
        }
    ]
}

If we add, remove or modify the array of people we expect Angular to detect that change and to re-render as necessary. In order to do this, Angular needs to determine if a change has occured. Sometimes this is easy, perhaps for simple string or number values, and sometimes this is much more difficult, perhaps for objects that are very large and complex and contains a lot of data.

We can can provide a tracking function that receives the individual item that is being iterated over and returns a unique value that Angular can use to detect changes. In our example, the id property of each object in the array of people is unique and is perfectly suited for this task.

First, we specify the trackBy function to the NgFor directive:

<h2>People</h2>
<div *ngFor="let person of people; trackBy: trackPerson;">
  {{ person.name }}
</div>

Then, we declare the tracking function in the directive's class:

export class AppComponent {
  trackByPerson(person) {
      return person.id;
    }
}

The tracking function is invoked with each item in the array of people and returns the unique id value that effectively enables Angular to detect changes.

 

I finished! On to the next chapter