【问题标题】:how to use track by inside ngFor angular 2如何在 ngFor angular 2 内部使用 track
【发布时间】:2016-07-19 06:47:16
【问题描述】:

尝试了所有我能猜到的语法都不能让它工作!

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

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

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

【问题讨论】:

  • 你能告诉我 ngFor 中 trackBy 的用途吗?埃里克的回答似乎很好。
  • @micronyks 它允许你将一个函数传递给*ngForNgFor 转发给https://angular.io/docs/ts/latest/api/core/IterableDifferFactory-interface.html github.com/angular/angular/blob/master/modules/angular2/src/…(虽然还不知道差异是如何工作的)
  • https://angular.io/docs/ts/latest/api/core/IterableDifferFactory-interface.html‌​ 未找到。还有其他链接吗?
  • 我仍然不清楚trackBy的干净用法。
  • 如果有人在*ngFor中发布使用trackBy的示例,我将非常有帮助

标签: angular ngfor angularjs-track-by


【解决方案1】:

正如@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>

这里你问 angular2 来

  1. 创建一个局部变量 post;
  2. 你告诉 trackBy 等到这个局部变量准备好“你可以通过使用 elvis 运算符 ' 后面的问号 变量名',然后将其 id 用作跟踪器。

所以

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

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

和angular的1一样

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

用法 2:使用您自己的函数进行跟踪

@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 可以取一个回调名称,它会为我们调用它,提供两个参数:循环的索引和当前项。

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

<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:post?.id”不起作用。就我而言,子元素的状态丢失了。一个单独的 trackBy 函数虽然有效(但绝对不方便)。顺便说一句,猫王操作员本身就表明出了点问题。如果它有效,那么你就不必在这里使用它(除非集合项可以为空)。
  • 我确认,trackBy 仅适用于函数,“post?.id”不会出错,但在这种情况下它会 trackBy“null”(您可以检查 html 并查看),这意味着它根本不跟踪,你只是看不到错误@Zalaboza 你能更新你的帖子,以免误导新用户吗?
  • 除了@Olivier 评论。从 Angular 2.4.1 开始,使用 *ngFor="#post of posts;trackBy:post?.id" 会抛出错误,因为 trackBy 只接受函数
  • 对@Zalaboza,只允许使用功能,请更新您的帖子。在这里讨论:github.com/angular/angular/issues/13641#issuecomment-269082370
  • @Zalaboza 请更新您的答案,trackBy:post?.id 已确认无效。
【解决方案2】:

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

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

官方文档指出https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html

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

【讨论】:

    【解决方案3】:

    除了其他人的答案之外,只想添加几个示例(Angular 2+)以明确使用 trackBy。

    来自文档:

    为避免这种昂贵的操作,您可以自定义默认值 跟踪算法。通过向 NgForOf 提供 trackBy 选项。 trackBy 接受一个有两个参数的函数:index 和 item。如果 trackBy 是给定的,Angular 通过返回值跟踪变化 功能。

    在此处阅读更多信息: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;
       }
    

    让我们使用*ngForarray显示到3个div中。

    app.component.html

    *ngFor 的示例没有 trackBy

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

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

    → 3 个 div 将被刷新。 自己试试,打开你的控制台验证一下。

    *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】:

      trackBy背后的概念:

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

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

      一个运行的例子:

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

      【讨论】:

      • 不知道为什么你有那个既没有运行也没有 trackby 示例的“运行示例”,但由于 trackby 背后的原因 +1。这只是为了提高性能。
      • @Rap 看起来很像从this blog post on trackBy 链接到的non-example-example ;^)
      • 为什么要显示该代码?此外,问题是关于 trackBy 的使用,而不是 为什么 使用它。官方文档和数十篇博客文章解释了为什么trackBy 很重要。
      猜你喜欢
      • 2019-01-28
      • 2018-06-13
      • 2019-08-10
      • 2019-05-02
      • 2017-07-23
      • 2017-09-20
      • 2017-04-13
      相关资源
      最近更新 更多