变更检测不适用于 NgFor 中使用的复杂对象
Change detection not working for complex objects used in NgFor
我正在使用 angular 7. 我有一个从 api 获取用户模型列表的父组件。当 "get" 成功时,它与 ngFor 循环结合使用,使用 @input 将每个用户注入子组件,这将显示用户列表。
更新单个用户模型上的 属性 时,子组件不会反映此更改。我明白为什么会这样。我知道只有在列表中的引用发生更改时才会启动更改检测。但是我不知道如何解决这个问题。我已经尝试将用户模型数组实现为可观察对象并使用异步管道,它在显示数据时起作用,但在进行更改时不起作用。
在我的具体示例中,我的用户模型上有一个 "selected" 属性,我的父组件上有一个 "select all" 按钮,我想用它来更改"selected" 属性 我数组中的所有用户,随后在 UI 上显示。这是我的代码的一个非常简单的版本
export class ParentComponent {
users: UserModel[];
ngOnInit() {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
onSelectAll() {
for (let user of this.users) {
user.selected = true;
}
}
}
父组件在模板中有以下内容:
<tr users-item [index]="i + 1" [user]="user" *ngFor="let user of users; let i = index"></tr>
这是使用用户模型显示数据的子组件:
export class ChildComponent {
@Input() user: UserModel;
firstname: string;
lastname: string;
selected: boolean;
ngOnChanges() {
if (this.user) {
this.firstname = this.user.firstname;
this.lastname = this.user.lastname;
this.selected = this.user.selected;
}
}
}
和子组件模板:
<td><input type="checkbox" [checked]="selected"></td>
<td>{{ fullname }}</td>
<td>{{ lastname }}</td>
下面部分代码看不懂。为什么要在 Table 行中传递输入?
<tr users-item [index]="i + 1" [user]="user" *ngFor="let user of users; let i = index"></tr>
输入的变化可以被子组件的 SimpleChanges 捕捉到。你应该尝试这样的事情。
ngOnChanges(changes: SimpleChanges) {
if (changes.user && changes.user.currentValue) {
this.firstname = changes.user.currentValue.firstname;
this.lastname = changes.user.currentValue.lastname;
this.selected = changes.user.currentValue.selected;
}
}
您可以简单地坚持基于不变性的方法并创建具有更新属性的浅表副本,而不是改变源对象。
在您的用例中,您可以通过更改 select all:
的实现来做到这一点
onSelectAll() {
this.users = this.users.map(user => this.mergeUser(user, {selected: true}));
}
private mergeUser(source: UserModel, updated: Partial<UserModel>): UserModel{
return {...source, ...updated};
}
我正在使用 angular 7. 我有一个从 api 获取用户模型列表的父组件。当 "get" 成功时,它与 ngFor 循环结合使用,使用 @input 将每个用户注入子组件,这将显示用户列表。
更新单个用户模型上的 属性 时,子组件不会反映此更改。我明白为什么会这样。我知道只有在列表中的引用发生更改时才会启动更改检测。但是我不知道如何解决这个问题。我已经尝试将用户模型数组实现为可观察对象并使用异步管道,它在显示数据时起作用,但在进行更改时不起作用。
在我的具体示例中,我的用户模型上有一个 "selected" 属性,我的父组件上有一个 "select all" 按钮,我想用它来更改"selected" 属性 我数组中的所有用户,随后在 UI 上显示。这是我的代码的一个非常简单的版本
export class ParentComponent {
users: UserModel[];
ngOnInit() {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
onSelectAll() {
for (let user of this.users) {
user.selected = true;
}
}
}
父组件在模板中有以下内容:
<tr users-item [index]="i + 1" [user]="user" *ngFor="let user of users; let i = index"></tr>
这是使用用户模型显示数据的子组件:
export class ChildComponent {
@Input() user: UserModel;
firstname: string;
lastname: string;
selected: boolean;
ngOnChanges() {
if (this.user) {
this.firstname = this.user.firstname;
this.lastname = this.user.lastname;
this.selected = this.user.selected;
}
}
}
和子组件模板:
<td><input type="checkbox" [checked]="selected"></td>
<td>{{ fullname }}</td>
<td>{{ lastname }}</td>
下面部分代码看不懂。为什么要在 Table 行中传递输入?
<tr users-item [index]="i + 1" [user]="user" *ngFor="let user of users; let i = index"></tr>
输入的变化可以被子组件的 SimpleChanges 捕捉到。你应该尝试这样的事情。
ngOnChanges(changes: SimpleChanges) {
if (changes.user && changes.user.currentValue) {
this.firstname = changes.user.currentValue.firstname;
this.lastname = changes.user.currentValue.lastname;
this.selected = changes.user.currentValue.selected;
}
}
您可以简单地坚持基于不变性的方法并创建具有更新属性的浅表副本,而不是改变源对象。
在您的用例中,您可以通过更改 select all:
的实现来做到这一点onSelectAll() {
this.users = this.users.map(user => this.mergeUser(user, {selected: true}));
}
private mergeUser(source: UserModel, updated: Partial<UserModel>): UserModel{
return {...source, ...updated};
}