Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use `trackBy` with `ngFor`

I can't really understand what I should return from trackBy. Based on some examples I've seen on the web, I should return the value of some property on the object. Is it right? Why should I get index as a parameter?

For example, in the following case:

Component.component.ts

constructor() {     window.setInterval(() => this.users = [             { name: 'user1', score: Math.random() },             { name: 'user2', score: Math.random() }         ],         1000); }  userByName(index, user) {     return user.name; } 

Component.template.html

<div *ngFor="let user of users; trackBy:userByName">   {{user.name}} -> {{user.score}} </div> 

The objects shown in this template are still updated despite the name being unchanged. Why?

like image 637
Max Koretskyi Avatar asked Feb 08 '17 08:02

Max Koretskyi


People also ask

How does ngFor trackBy work?

The trackBy function takes the index and the current item as arguments and needs to return the unique identifier for this item. Now when you change the collection, Angular can track which items have been added or removed according to the unique identifier and create or destroy only the items that changed. That's all.

What is trackBy in ngFor Angular?

Angular provides a method called trackBy , which is used to track our incoming data every time we get a request from an API. Suppose we have some data coming from an API request into the collection, and we need to change the data over the web page using the ngFor directive.

Why must you use the ngFor directive in conjunction with the trackBy function?

Why use trackyBy with ngFor directive : ngFor directive may perform poorly with large lists. A small change to the list like, adding a new item or removing an existing item may trigger several DOM manipulations.


1 Answers

On each ngDoCheck triggered for the ngForOf directive, Angular checks what objects have changed. It uses differs for this process and each differ uses the trackBy function to compare the current object with the new one. The default trackBy function tracks items by identity:

const trackByIdentity = (index: number, item: any) => item; 

It receives the current item and should return some value. Then the value returned by the function is compared against the value this function returned the last time. If the value changes, the differ reports a change. So if the default function returns object references, it will not match the current item if the object reference has changed. So you can provide your custom trackBy function that will return something else. For example, some key value of the object. If this key value matches the previous one, then Angular will not detect the change.

The syntax ...trackBy:userByName is no longer supported. You must now provide a function reference. Here is the basic example:

setInterval( () => {   this.list.length = 0;   this.list.push({name: 'Gustavo'});   this.list.push({name: 'Costa'}); }, 2000);  @Component({   selector: 'my-app',   template: `    <li *ngFor="let item of list; trackBy:identify">{{item.name}}</li>   ` }) export class App {   list:[];    identify(index, item){      return item.name;    } 

Although the object reference changes, the DOM is not updated. Here is the plunker. If you're curious how ngFor works under the hood, read this answer.

like image 182
Max Koretskyi Avatar answered Sep 20 '22 10:09

Max Koretskyi