how to use track by inside ngFor angular 2

扶醉桌前 提交于 2019-11-27 01:39:53
Zalaboza

As pointed out in @Eric comment, and after lots of reading and playing around, here is how to use trackBy in angular2

  1. the first thing you need to know its not same syntax as angular1, now you need to separate it from the for loop with a ;.

Usage 1: Track by property of object

 // starting v2. 1 this will throw error, you can only use functions in trackBy from now on

<ion-card *ngFor="let post of posts;trackBy:post?.id">
</ion-card> // **DEPRECATED**
---or---
<ion-card *ngFor="let post of posts;trackBy:trackByFn">
</ion-card>

here you ask angular2 to

  1. create a local variable post;
  2. you tell trackBy to wait untill this local variable is ready "you do that by using elvis operator 'the question mark after the variable name', then use its id as tracker.

so

// starting v2. 1 this will throw error, you can only use functions in trackBy from now on

*ngFor="#post of posts;trackBy:post?.id"

is what same as angular's 1

ng-repeat="post in posts track by post.id"

Usage 2: Track using your own Function

@Page({
    template: `
        <ul>
            <li *ngFor="#post of posts;trackBy:identify">
              {{post.data}}
            </li>
        </ul>
    `
})
export class HomeworkAddStudentsPage {
    posts:Array<{id:number,data:string}>;   

    constructor() {
        this.posts = [  {id:1,data:'post with id 1'},
                        {id:2,data:'post with id 2'} ];
    }

    identify(index,item){
      //do what ever logic you need to come up with the unique identifier of your item in loop, I will just return the object id.
      return post.id 
     }

}

trackBy can take a name of callback, and it will call it for us supplying 2 parameters: the index of the loop and the current item.

To achieve the same with Angular 1, I used to do:

<li ng-repeat="post in posts track by identify($index,post)"></li>

app.controller(function($scope){
  $scope.identify = function(index, item) {return item.id};
});

As you already recognized, using a function is the only way to use trackBy in Angular 2

<ion-card *ngFor="#post of posts;trackBy:identify"></ion-card>

The official documentation states that https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html

All the other information about <ion-card *ngFor="let post of posts;trackBy:post?.id"></ion-card> is wrong. Starting with Angular 2.4.1 this will also throw an error in the application.

Ruchi Wadhwa

The concept behind trackBy:

  1. ngFor of angular automatically optimizes the display of modified/created/deleted objects by tracking through object identity. So, if you create all new objects in the list and then use ngFor, it will render whole list.

  2. Let's consider a scenario where despite of all ngFor optimizations, the rendering is still taking time. In that case we use trackBy. So that, we can provide another parameter to track objects than the object identity which is a default tracking criteria.

A running example:

<!DOCTYPE html>
<html>

<head>
    <title>Angular 2.1.2 + TypeScript Starter Kit</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <script src="https://unpkg.com/zone.js@0.6.21/dist/zone.js"></script>
    <script src="https://unpkg.com/reflect-metadata@0.1.9/Reflect.js"></script>
    <script src="https://unpkg.com/systemjs@0.19.41/dist/system.js"></script>
    <script src="https://unpkg.com/typescript@2.1.4/lib/typescript.js"></script>
    <script src="config.js"></script>
  <script>
      System.import('app')
          .catch(console.error.bind(console));
    </script>
</head>

<body>
    <my-app>
        loading...
    </my-app>
</body>

</html>

This simple solution worked for my scenario

<ion-card *ngFor="let post of posts;let i = index"> 
    {{i+1}}
</ion-card>

EDIT: As suggested by Jeremy Thille below, you should use let instead of #, as # is deprecated in the latest versions of Angular2.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!