Menu Close

Angular ngFor trackBy

In this article we will learn about Angular ngFor trackBy. Angular Trackby option improves the Performance of the ngFor if the collection has a large no of items and keeps changing. Learn why we need it and how to use it to improve the performance of the ngFor. Please read my previous article ngFor Directive in Angular.

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.

Modify the Component Typescript

  • On the page load we have list of 8 items and on the click event we have added two more items.
getAllCricketers(){
    this.cricketerList= [

      { id: 1, name: 'Rahuld Dravid', hundreds: 48, country: 'India' },
      { id: 2, name: 'Sachin Tendulkar', hundreds: 100, country: 'India' },
      { id: 3, name: 'Saurrav Ganguly', hundreds: 38, country: 'India' },
      { id: 4, name: 'Mahendra Singh Dhoni', hundreds: 16, country: 'India' },
      { id: 5, name: 'Virat Kohli', hundreds: 71, country: 'India' },
      { id: 6, name: 'Ricky Ponting', hundreds: 71, country: 'Australia ' },
      { id: 7, name: 'Steven Smith', hundreds: 27, country: 'Australia' },
      { id: 8, name: 'Kane Willimison', hundreds: 51, country: 'Newzealand' },
      { id: 8, name: 'Babar Azam', hundreds: 24, country: 'Pakistan' }
    ];
  }
  getNewCricketers(){
    this.cricketerList.push({ id: 9, name: 'David Warner', hundreds: 30, country: 'Australia' });
    this.cricketerList.push({ id: 10, name: 'Md. Rizwan', hundreds: 14, country: 'Pakistan' });
  }

<table class='table table-stripped'>
  <thead>
    <tr>
      <th>No</th>
      <th>Name</th>
      <th>No. of Hundreds</th>
      <th>Country</th>
      <th>IsEven</th>
      <th>IsOdd</th>
    </tr>
  </thead>
  <tbody>
    <ng-container *ngFor="let cricketer of cricketerList;let isEven = even; let isOdd = odd;">
      <tr>
        <td>{{cricketer.id}}</td>
        <td>{{cricketer.name}}</td>
        <td>{{cricketer.hundreds}}</td>
        <td>{{cricketer.country}}</td>
        <td>{{isEven}}</td>
        <td>{{isOdd}}</td>
      </tr>
    </ng-container>
  </tbody>
</table>
<button (click)="getNewCricketers()">More Items</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 8 list which are initialized through the constructor and when you click on the “More Item” button it will load more items.

ngTrackBy-LoadItems

Internally it won’t add the two lines only, it destroy the previous list and added whole list back, let’s confirm here.

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 rest of the 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.

So, Final changes would be like this.

import { Component, OnInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-cricketer-list',
  templateUrl: './cricketer-list.component.html',
  styleUrls: ['./cricketer-list.component.css'],
  encapsulation: ViewEncapsulation.Emulated,
})
export class CricketerListComponent implements OnInit {

  cricketerList: Cricketer[]=[];
  constructor() { }
  ngOnInit(): void {
   this.getAllCricketers();
  }
  getAllCricketers(){
    this.cricketerList= [
      { id: 1, name: 'Rahuld Dravid', hundreds: 48, country: 'India' },
      { id: 2, name: 'Sachin Tendulkar', hundreds: 100, country: 'India' },
      { id: 3, name: 'Saurrav Ganguly', hundreds: 38, country: 'India' },
      { id: 4, name: 'Mahendra Singh Dhoni', hundreds: 16, country: 'India' },
      { id: 5, name: 'Virat Kohli', hundreds: 71, country: 'India' },
      { id: 6, name: 'Ricky Ponting', hundreds: 71, country: 'Australia ' },
      { id: 7, name: 'Steven Smith', hundreds: 27, country: 'Australia' },
      { id: 8, name: 'Kane Willimison', hundreds: 51, country: 'Newzealand' },
      { id: 8, name: 'Babar Azam', hundreds: 24, country: 'Pakistan' }
    ];
  }
  getNewCricketers(){
    this.cricketerList.push({ id: 9, name: 'David Warner', hundreds: 30, country: 'Australia' });
    this.cricketerList.push({ id: 10, name: 'Md. Rizwan', hundreds: 14, country: 'Pakistan' });
  }
  getAllCricketerListCount(): number {
    return this.cricketerList.length;
  }
  getAllCricketerList(): any {
    return this.cricketerList;
  }
  identify(index: number, item: any){
    return item.name; 
 }
}
export class Cricketer {
  id: number = 0;
  name: string = '';
  hundreds: number = 0;
  country: string = '';
}

Here in the HTML we added trackBy in *ngFor

<table class='table table-stripped'>
  <thead>
    <tr>
      <th>No</th>
      <th>Name</th>
      <th>No. of Hundreds</th>
      <th>Country</th>
      <th>IsEven</th>
      <th>IsOdd</th>
    </tr>
  </thead>
  <tbody>
    <ng-container *ngFor="let cricketer of cricketerList;let isEven = even; let isOdd = odd; trackBy:identify;">
      <tr>
        <td>{{cricketer.id}}</td>
        <td>{{cricketer.name}}</td>
        <td>{{cricketer.hundreds}}</td>
        <td>{{cricketer.country}}</td>
        <td>{{isEven}}</td>
        <td>{{isOdd}}</td>
      </tr>
    </ng-container>
  </tbody>
</table>
<button (click)="getNewCricketers()">More Items</button>

The Final output like below,

Conclusion

In this article we discussed about Angular ngFor trackBy. Angular Trackby option improves the Performance of the ngFor if the collection has a large no of items and keeps changing.

Leave behind your valuable queries, suggestions in the comment section below. Also, if you think this article help to you, do not forget to share this within your developer community. Happy Coding 🙂

Related Articles

Jayant Tripathy
Coder, Blogger, YouTuber

A passionate developer keep focus on learning and working on new technology.

Leave a Reply

Your email address will not be published.