Angular global ngFor track by property directive with strict type checking.
Nigro Simone
Posted on March 5, 2022
When displaying a list of data (at least somewhat large lists) you should be using Angular's trackBy feature which looks something like:
import { Component } from '@angular/core';
interface Item {
id: number;
name: string;
}
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let item of list; trackBy: trackById">
{{ item.id }} {{ item.name }}
</li>
</ul>
`,
})
export class AppListComponent {
public list: Array<Item> = [
{ id: 0, name: 'foo' },
{ id: 1, name: 'bar' },
{ id: 2, name: 'baz' },
];
public trackById(index: number, item: Item) {
return item.id;
}
}
Unfortunately, Angular forces us to write a tracking function in each component in which we want to make use of trackBy. With ng-for-track-by-property
you could just handle this entirely in the template by passing a property like this:
import { Component } from '@angular/core';
interface Item {
id: number;
name: string;
}
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let item of list; trackByProperty: 'id'">
{{ item.id }} {{ item.name }}
</li>
</ul>
`,
})
export class AppListComponent {
public list: Array<Item> = [
{ id: 0, name: 'foo' },
{ id: 1, name: 'bar' },
{ id: 2, name: 'baz' },
];
}
ng-for-track-by-property
has strict type checking and only available property are allowed
Get Started
Step 1: install ng-for-track-by-property
npm i ng-for-track-by-property
Step 2: Import NgForTrackByPropertyModule
into your app module, eg.:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { CommonModule } from '@angular/common';
import { NgForTrackByPropertyModule } from 'ng-for-track-by-property';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
CommonModule,
NgForTrackByPropertyModule,
],
providers: [],
bootstrap: [AppComponent],
],
})
export class AppModule { }
Step 3: add trackByProperty
to your ngFor
, eg.:
import { Component } from '@angular/core';
interface Item {
id: number;
name: string;
}
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let item of list; trackByProperty: 'id'">
{{ item.id }} {{ item.name }}
</li>
</ul>
`,
})
export class AppComponent {
public list: Array<Item> = [
{ id: 0, name: 'foo' },
{ id: 1, name: 'bar' },
{ id: 2, name: 'baz' },
];
}
you can also track by index with trackByIndex
, eg.:
import { Component } from '@angular/core';
interface Item {
id: number;
name: string;
}
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let item of list; trackByIndex">
{{ item.id }} {{ item.name }}
</li>
</ul>
`,
})
export class AppComponent {
public list: Array<Item> = [
{ id: 0, name: 'foo' },
{ id: 1, name: 'bar' },
{ id: 2, name: 'baz' },
];
}
since track by property id is a very common case, there is also trackById
:
import { Component } from '@angular/core';
interface Item {
id: number;
name: string;
}
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let item of list; trackById">
{{ item.id }} {{ item.name }}
</li>
</ul>
`,
})
export class AppComponent {
public list: Array<Item> = [
{ id: 0, name: 'foo' },
{ id: 1, name: 'bar' },
{ id: 2, name: 'baz' },
];
}
See:
Posted on March 5, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.