DEV Community

Nigro Simone
Nigro Simone

Posted on

Angular global ngFor track by property directive with strict type checking.

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; } } 
Enter fullscreen mode Exit fullscreen mode

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' }, ]; } 
Enter fullscreen mode Exit fullscreen mode

ng-for-track-by-property has strict type checking and only available property are allowed
Image description

Get Started

Step 1: install ng-for-track-by-property

npm i ng-for-track-by-property 
Enter fullscreen mode Exit fullscreen mode

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 { } 
Enter fullscreen mode Exit fullscreen mode

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' }, ]; } 
Enter fullscreen mode Exit fullscreen mode

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' }, ]; } 
Enter fullscreen mode Exit fullscreen mode

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' }, ]; } 
Enter fullscreen mode Exit fullscreen mode

See:

Top comments (0)