如何在ngFor angular 2中使用track

时间:2016-03-31 01:57:07

标签: angular ngfor angularjs-track-by

尝试了我能猜到的每种语法都无法使其正常工作!

<!--- THIS WORKS FINE --->
<ion-card *ngFor="#post of posts">
{{post|json}}
</ion-card>

<!--- BLANK PAGE --->
<ion-card *ngFor="#post of posts track by post.id">
{{post|json}}
</ion-card>

<!--- Exception : Cannot read property 'id' of undefined --->
<ion-card *ngFor="#post of posts;trackBy:post.id">
{{post|json}}
</ion-card>

<!--- Exception : Cannot read property 'undefined' of undefined --->
<ion-card *ngFor="#post of posts;trackBy:posts[index].id">
{{post|json}}
</ion-card>

<!--- Blank page no exception raised !  --->
<ion-card *ngFor="#post of posts;#index index;trackBy:posts[index].id">
{{post|json}}
</ion-card>

对我有用的唯一方法是

  1. 在控制器类中创建方法

    标识(索引,交张贴){   返回post.id }

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

    这是唯一的方法吗?我不能只为trackBy指定内联属性名称吗?

5 个答案:

答案 0 :(得分:79)

正如在@Eric评论中所指出的,经过大量的阅读和游戏,这里是如何在angular2中使用trackBy

  1. 首先你需要知道它与angular1的语法不同,现在你需要将它与for // 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> 的for循环分开。
  2. 用法1:按对象属性进行跟踪

    // starting v2. 1 this will throw error, you can only use functions in trackBy from now on
    
    *ngFor="#post of posts;trackBy:post?.id"
    

    这里你问angular2到

    1. 创建一个本地变量帖子;
    2. 你告诉trackBy要等到这个局部变量准备就绪了#34;你是通过使用elvis运算符&#39;之后的问号来做到的 变量名称&#39;,然后使用其id作为跟踪器。
    3. 所以

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

      与angular&#39; s

      相同
      @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 
           }
      
      }
      

      用法2:使用您自己的功能跟踪

      <li ng-repeat="post in posts track by identify($index,post)"></li>
      
      app.controller(function($scope){
        $scope.identify = function(index, item) {return item.id};
      });
      

      trackBy可以采用回调的名称,它将为我们提供2个参数来调用它:循环的索引和当前项。

      为了实现与Angular 1的相同,我曾经这样做:

      nrMessages

答案 1 :(得分:9)

正如您已经认识到的那样,使用函数是在Angular 2中使用trackBy的唯一方法

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

官方文件指出QueryBuilders

有关<ion-card *ngFor="let post of posts;trackBy:post?.id"></ion-card>的所有其他信息都是错误的。从Angular 2.4.1开始,这也会在应用程序中引发错误。

答案 2 :(得分:2)

trackBy背后的概念:

    角色的
  1. ngFor通过跟踪对象标识自动优化修改/创建/删除对象的显示。 因此,如果您在列表中创建所有新对象,然后使用ngFor,它将呈现整个列表。

  2. 让我们考虑一个场景,尽管进行了所有ngFor次优化,渲染仍然需要时间。在这种情况下,我们使用trackBy。因此,我们可以提供另一个参数来跟踪对象,而不是作为默认跟踪条件的对象标识。

  3. 一个正在运行的例子:

    <!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>
    

答案 3 :(得分:2)

除了其他人的答案外,只想添加一些示例(Angular 2+),以便清楚地使用trackBy。

摘自文档:

  

为避免此昂贵的操作,您可以自定义默认值   跟踪算法。通过向NgForOf提供trackBy选项。   trackBy采用的函数具有两个参数:index和item。如果   给出trackBy,角度轨迹会根据   功能。

在此处了解更多信息:https://angular.io/api/common/NgForOf

一个例子会更好地解释它。

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;
   }

让我们使用array*ngFor显示为3格。

app.component.html

*ngFor 没有trackBy 的示例:

<div *ngFor="let e of array;">
   {{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>

如果我们点击foo按钮会发生什么?

→3格将被刷新。 尝试一下,打开控制台进行验证。

*ngFor 带有trackBy 的示例:

<div *ngFor="let e of array; trackBy: identify">
   {{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>

如果我们点击foo按钮会发生什么?

→仅刷新第一个div。 尝试一下,打开控制台进行验证。

如果我们更新第一个对象而不是整个对象怎么办?

   foo() {
      this.array[0].name = "foo";
   }

→此处无需使用trackBy

在使用 Subscription (通常类似于我用array模式化的内容)时,它特别有用。因此,它看起来像:

   array = [];
   subscription: Subscription;

   ngOnInit(): void {
      this.subscription = this.fooService.getArray().subscribe(data => {
         this.array = data;
      });
   }

   identify(index, item) {
      return item.id;
   }

答案 4 :(得分:-5)

这个简单的解决方案适用于我的场景

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

编辑:根据Jeremy Thille的建议,您应该使用let代替#,因为最新版本的Angular2中不推荐使用#