As this topic is still active & finding a clear answer is difficult let me add few examples in addition to @Max's answer:
app.component.ts
array = [
{ "id": 1, "name": "bill" },
{ "id": 2, "name": "bob" },
{ "id": 3, "name": "billy" }
]
foo() {
this.array = [
{ "id": 1, "name": "foo" },
{ "id": 2, "name": "bob" },
{ "id": 3, "name": "billy" }
]
}
identify(index, item) {
return item.id;
}
Let's display the array
into 3 divs using *ngFor
.
app.component.html
Example of *ngFor
without trackBy:
<div *ngFor="let e of array;">
{{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>
What happens if we click the foo
button ?
→ The 3 divs will be refreshed. Try it yourself, open your console to verify.
Example of *ngFor
with trackBy:
<div *ngFor="let e of array; trackBy: identify">
{{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>
What happens if we click the foo
button ?
→ Only the first div will be refreshed. Try it yourself, open your console to verify.
And what if we updated the first object instead of the whole object ?
foo() {
this.array[0].name = "foo";
}
→ There is no need to use trackBy
here.
It's especially useful when using a Subscription which often looks like what I schematized with array
. So it would look like:
array = [];
subscription: Subscription;
ngOnInit(): void {
this.subscription = this.fooService.getArray().subscribe(data => {
this.array = data;
});
}
identify(index, item) {
return item.id;
}
From the documentation:
To avoid this expensive operation, you can customize the default
tracking algorithm. by supplying the trackBy option to NgForOf.
trackBy takes a function that has two arguments: index and item. If
trackBy is given, Angular tracks changes by the return value of the
function.
Read more here: https://angular.io/api/common/NgForOf
Find my original answer here: https://mcmap.net/q/144178/-how-to-use-track-by-inside-ngfor-angular-2
let user of users; let index=index; trackBy:userByName(index,user)
? – PerlitengTrackBy
come in – Triadelphous