Angular ngFor trackBy

Angular ngFor trackBy with Examples

In this article, I am going to discuss the Angular ngFor trackBy with some examples. Please read our previous article before proceeding to this article where we discussed Angular ngFor Directive in detail. The Angular trackBy is used to improve the performance of an angular application. At the end of this article, you will understand what exactly is Angular ngFor trackBy and when and how to use this in Angular Application.

Why do we need the Angular ngFor trackBy? 

The use of trackBy is to improve the performance of the angular application. It is usually not needed by default but needed only when your application running into performance issues.

The Angular ngFor directive may perform poorly with the large collections.  A small change to the collection such as adding a new item or removing an existing item from the collection may trigger a cascade of DOM manipulations.

Suppose, we have some data coming from some API and we are storing these data into some kind of collection like an array and then we need to update these data over the webpage using ngFor directive. By default, what angular framework will do is, it will remove all the DOM elements that are associated with the data and will create them again in the DOM tree even if the same data is coming. That means a lot of DOM Manipulation will happen in the background if a large amount of data coming from the API again and again.

Example to understand ngFor trackBy in Angular Application:

Let us understand the need for angular ngFor trackBy with an example step by step.

Step1: Modify app.component.ts file as shown below.

Open app.component.ts file and then copy and paste the following in it. As you can see in the below code, the constructor of the AppComponent class initializes the student’s collection property with 3 students’ objects. On the other hand, the getStudents() method of the AppComponent class update the same student’s collection property with 5 student objects (the 3 existing students plus another two new student object).

import { Component } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  students: any[];

    constructor() {
        this.students = [
            {
                ID: 'std101', FirstName: 'Santosh', LastName: 'Jena', Branch: 'CSE',
                DOB: '29/02/1988', Gender: 'Male'
            },
            {
                ID: 'std102', FirstName: 'Anurag', LastName: 'Mohanty', Branch: 'ETC',
                DOB: '23/05/1989', Gender: 'Male'
            },
            {
                ID: 'std103', FirstName: 'Priyanka', LastName: 'Dewangan', Branch: 'CSE',
                DOB: '24/07/1992', Gender: 'Female'
            },
        ];
    }

    getStudents(): void {
        this.students = [
            {
                ID: 'std101', FirstName: 'Santosh', LastName: 'Jena', Branch: 'CSE',
                DOB: '29/02/1988', Gender: 'Male'
            },
            {
                ID: 'std102', FirstName: 'Anurag', LastName: 'Mohanty', Branch: 'ETC',
                DOB: '23/05/1989', Gender: 'Male'
            },
            {
                ID: 'std103', FirstName: 'Priyanka', LastName: 'Dewangan', Branch: 'CSE',
                DOB: '24/07/1992', Gender: 'Female'
            },
            {
                ID: 'std104', FirstName: 'Hina', LastName: 'Sharma', Branch: 'ETC',
                DOB: '19/08/1990', Gender: 'Female'
            },
            {
                ID: 'std105', FirstName: 'Sambit', LastName: 'Satapathy', Branch: 'CSE',
                DOB: '12/94/1991', Gender: 'Male'
            }
        ];
    } 
}
Step2: Modify the app.component.css file

We are going to use some styles in our HTML page. So, open app.component.css file and then copy and paste the following code in it.

table {
    color: #369;
    font-family: Arial, Helvetica, sans-serif;
    font-size: large;
    border-collapse: collapse;
}

td {
    border: 1px solid #369;
    padding:5px;
}

th{
    border: 1px solid #369;
    padding:5px;
}
Step3: Modify app.module.ts file

Open your root module i.e. app.module.ts file and then copy and paste the following code in it.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],

  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule
  ],

  providers: [],
  bootstrap: [AppComponent] 
})

export class AppModule { }
Step4: Modify app.component.html file

Open app.component.html file and then copy and paste the following code in it.

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Branch</th>
            <th>DOB</th>
            <th>Gender</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor='let student of students'>
            <td>{{student.ID}}</td>
            <td>{{student.FirstName}}</td>
            <td>{{student.LastName}}</td>
            <td>{{student.Branch}}</td>
            <td>{{student.DOB}}</td>
            <td>{{student.Gender}}</td>
        </tr>
    </tbody>
</table>
<br />
<button (click)='getStudents()'>Refresh Students</button>

In the above HTML, at the moment we are not using the trackBy with ngFor directive. So when the page loads for the first time you will see 3 students which are initialized through the constructor of the AppComponent class and when you click on the “Refresh Students” button, then you will see the 4th and 5th students as well as shown in the below image.

Angular ngFor trackBy with Examples

Now you may think that it just added the additional rows for the 4th and 5th students but that’s not true. It internally destroyed all the <tr> and <td> elements of all the students and then recreated them. To confirm this launch the browser developer tools by pressing the F12 key. Then click on the “Elements” tab and expand the <table> and then <tbody> elements.

At this point click on the “Refresh Students” button and you will notice that all the <tr> elements are briefly highlighted indicating that they are destroyed and recreated as shown in the below image.

Why do we need the Angular ngFor trackyBy? 

This is because Angular Framework by default keeps track of the objects using the object references. So, when you click on the “Refresh Students” button, it will get different object references and as a result, Angular has no other choices but to delete all the old DOM elements and insert the new DOM elements. Image what could happen if the data size is huge.

How to solve the above problem?

In order to solve the above performance issue problem, the angular framework provides one function called trackBy which will help us to track the items which have been added or removed. The trackBy function will take two arguments, first is the index and the second one is the current item and it will return one unique identifier as return a value using which we can track that item. In our example, we are going to track by Student ID as the student id is unique for each student.

In order to use trackBy, add the following method in the app.component.ts file.  

trackByStudentID(index: number, student: any): string {
       return student.ID;
}

Then do the following changes in the app.component.html file:

<tr *ngFor=’let student of students; trackBy:trackByStudentID’>

Here we are using the trackBy along with ngFor directive. At this point, run the application and then launch the browser developer tools by pressing the F12 key. When you click on the “Refresh Students” button for the first time, then you can notice that only the 4th and 5th rows of the students are highlighted indicating that only those <tr> elements are added.

On the subsequent clicks, nothing is highlighted meaning none of the <tr> elements are destroyed or added as the students’ collection has not changed. Each and every time when you click on the “Refresh Students” button you get different object references, but as the Angular is now tracking the student objects using the Student Id instead of object references, as a result, the respective DOM elements are not affected. 

In the next article, I am going to discuss Angular ngIf Directive with then and else block in detail with some examples. Here, in this article, I try to explain the Angular ngFor trackBy with examples. I hope this article will help you with your needs. I would like to have your feedback. Please post your feedback, question, or comments about this article.

Leave a Reply

Your email address will not be published. Required fields are marked *