当前位置: 首页 > 知识库问答 >
问题:

如何将“trackBy”与“ngFor”一起使用

万俟嘉珍
2023-03-14

我真的不明白我应该从< code>trackBy返回什么。根据我在网上看到的一些例子,我应该返回对象的一些属性值。对不对?为什么我应该获取< code>index作为参数?

例如在以下情况下:

组件.组件. ts

constructor() {
    window.setInterval(() => this.users = [
            { name: 'user1', score: Math.random() },
            { name: 'user2', score: Math.random() }
        ],
        1000);
}

userByName(index, user) {
    return user.name;
}

组件.模板.html

<div *ngFor="let user of users; trackBy:userByName">
  {{user.name}} -> {{user.score}}
</div>

尽管名称未更改,此模板中显示的对象仍会更新。为什么?

共有3个答案

慕乐池
2023-03-14

这是我在我的项目中使用允许跟踪

import { Host, Directive, Input } from "@angular/core";
import { NgForOf } from "@angular/common";

@Directive({
    selector: "[ngForTrackByProperty]"
})
export class TrackByPropertyDirective {

    private _propertyName: string = "";

    public constructor(@Host() private readonly _ngFor: NgForOf<any>) {
        this._ngFor.ngForTrackBy = (_: number, item: any) => this._propertyName ? item[this._propertyName] : item;
    }

    @Input("ngForTrackByProperty")
    public set propertyName(value: string | null) {
        // We must accept null in case the user code omitted the ": 'somePropName'" part.
        this._propertyName = value ?? "";
    }

}

用法:

<some-tag *ngFor="let item of models; trackByProperty: 'yourDiscriminantProp'">

司徒高寒
2023-03-14

因为这个话题仍然活跃

应用程序组件

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

让我们显示数组<代码> < /代码> 3 div

app.component.html

*ngFor 不带跟踪的示例通过:

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

如果我们点击<代码> foo > < /代码的屁股

→ 将刷新3个div。自己试试,打开控制台进行验证。

带有trackBy的*ngFor示例:

<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

当使用订阅时,它特别有用,它通常看起来像我用数组架构化的内容。所以它看起来像这样:

 array = [];
 subscription: Subscription;

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

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

从文档中:

为了避免这种昂贵的操作,您可以自定义默认的跟踪算法。通过向NgForOf提供trackBy选项。trackBy采用一个有两个参数的函数:index和item。如果给定trackBy,则角度轨迹会随函数的返回值而变化。

阅读更多信息:https://angular.io/api/common/NgForOf

发现我原来的答案:https://stackoverflo

堵乐
2023-03-14

在为< code>ngForOf指令触发的每个< code>ngDoCheck上,Angular检查哪些对象已更改。它为此过程使用different,每个different使用< code> trackBy函数将当前对象与新对象进行比较。默认的< code>trackBy函数按标识跟踪项目:

const trackByIdentity = (index: number, item: any) => item;

它接收当前项,应该返回一些值。然后将该函数返回的值与该函数上次返回的值进行比较。如果值发生变化,differ会报告一个变化。因此,如果默认函数返回对象引用,并且对象引用已经更改,那么它将不会匹配当前项。因此,您可以提供自定义的< code>trackBy函数,该函数将返回其他内容。例如,对象的某个键值。如果这个键值与前一个键值匹配,那么Angular将不会检测到更改。

语法<代码>…trackBy: userByName > < /代码是n

setInterval( () => {
  this.list.length = 0;
  this.list.push({name: 'Gustavo'});
  this.list.push({name: 'Costa'});
}, 2000);

@Component({
  selector: 'my-app',
  template: `
   <li *ngFor="let item of list; trackBy:identify">{{item.name}}</li>
  `
})
export class App {
  list:[];

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

尽管对象引用发生了变化,但DOM不会更新。这是普朗克。如果您想知道ngFor在引擎盖下是如何工作的,请阅读以下答案。

 类似资料:
  • 我在Ubuntu 14.04中安装了phpbrew以使用PHP5.4。它工作得很好,但当我尝试使用composer时除外,composer会忽略phpbrew并安装与PHP5.5相关的依赖项。 有没有办法强制composer与phpbrew config兼容?我试图在我的作曲家中添加:php:“5.4”。json,但是它说这个要求在我的php版本中是不可能的。

  • 我是Micronaut框架的新手,我正在尝试使用entitymanager创建我的存储库。我这样创建了我的存储库 我使用这个类实现接口并注入entitymanager 问题是我一直有这个错误: PS:我已经启用了注释处理

  • 我正在尝试将composer与我的WampServer一起使用。 我所有文件的路径都是,但当我运行composer时,它会将供应商文件和其他东西安装到其他地方。 我甚至不知道我的项目在哪里,我也不能改变我的项目在哪里的路径。我已经尝试了所有的方法,但它似乎仍然没有在我的项目文件夹中安装供应商文件。

  • API level 28和Google建议使用registerNetworkCallback(NetworkRequest,PendingIntent)不推荐CONNECTIVITY\u操作。 我尝试使用ConnectionManager注册了registerNetworkCallback。NetworkCallback和它的工作,但我想使用PendingContent。 让我困惑的是公共空寄存器

  • 问题内容: 当我尝试将Webpack与简单的Express服务器一起使用时,总是会收到大量错误消息: express.js 我得到所有这些错误: 这是我的配置文件: 我该怎么办,我还需要在服务器端使用webpack。 我像这样运行express.js文件: 问题答案: 我最终要做的是,我使用了两种不同的配置,一种用于使用webpack将服务器内容打包在一起,另一种用于将所有浏览器内容打包在一起,并

  • 我有两个多对多关系的实体。 在类角色中: java.lang.StackOverflowError:空 我该如何解决这个问题?我在Stackoverflow上看到了类似的问题,但我没有找到真正有效的解决方案。 Upd:抛出异常的位置: