ngFor 依赖于另一个 ngFor 来完成渲染——获取 ExpressionChangedAfterItHasBeenCheckedError [Angular 2]
ngFor depends on another ngFor to finish rendering - getting ExpressionChangedAfterItHasBeenCheckedError [Angular 2]
我有两个组件列表,它们使用两个不同服务提供的数据:
- 第一个列表包含一些具有随机高度的组件(在渲染之前我不知道它们的高度)
- 第二个列表中的组件必须根据第一个列表中组件的高度计算高度。
两个列表都是由同一个组件使用两个 *ngFor 循环生成的,服务数据是从另一个子组件更改的。
问题是当模型数据发生变化时,两个 ngFor 循环都尝试更新模板,但第二个失败,因为它依赖于尚未准备好的第一个 ngFor。
我确实尝试使用 ChangeDetectorRef.detectChanges() 或监听包含第一个列表组件的 QueryList 发出的更改,但我仍然收到 ExpressionChangedAfterItHasBeenCheckedError。
实际情况有点复杂,但这里是代码的简化版本:
https://embed.plnkr.co/sr9k0wLQtyWSATiZuqaK/
提前致谢,这是我关于 Whosebug 的第一个问题:)
我会避免使用在模板内计算高度的方法。相反,我会准备数据以供查看:
<second-cmp
*ngFor="let cmp of generatedData"
[model]="cmp"
[height]="cmp.height"> <------------ already calculated value
然后我会订阅 QueryList.changes
来跟踪生成元素的变化并计算 height
那里:
constructor(
...,
private cdRef: ChangeDetectorRef) {}
ngAfterViewInit() {
this.components.changes.subscribe(components => {
const renderedCmps = components.toArray();
this.generatedData.forEach((x, index) => {
switch (index) {
case 0: // first
x.height = renderedCmps[0].height / 2;
break;
case this.modelData.length: // last
x.height = (renderedCmps[renderedCmps.length - 1].height / 2);
break;
default: // in-between
x.height = (renderedCmps[index - 1].height + renderedCmps[index].height) / 2
}
});
this.cdRef.detectChanges();
});
}
+ 'px'
是多余的,因为我们可以在样式绑定中指定它:
[style.height.px]="height"
反应非常好@yurzui,效果很好!
在模型数据上设置高度 属性 也消除了单独绑定它的必要性,因为我已经将整个模型的引用传递给 *ngFor 中的组件。
<second-cmp
*ngFor="let cmp of generatedData"
[model]="cmp"> <!-- the height doesn't need to be binded separately anymore -->
@Component({
selector: 'second-cmp',
template: `
<li>
<div class="item" [style.height.px]="model.height">Calculated height</div>
</li>`
)}
export class Second {
@Input('model') model;
// @Input('height') height; <-- removed
}
我有两个组件列表,它们使用两个不同服务提供的数据:
- 第一个列表包含一些具有随机高度的组件(在渲染之前我不知道它们的高度)
- 第二个列表中的组件必须根据第一个列表中组件的高度计算高度。
两个列表都是由同一个组件使用两个 *ngFor 循环生成的,服务数据是从另一个子组件更改的。
问题是当模型数据发生变化时,两个 ngFor 循环都尝试更新模板,但第二个失败,因为它依赖于尚未准备好的第一个 ngFor。
我确实尝试使用 ChangeDetectorRef.detectChanges() 或监听包含第一个列表组件的 QueryList 发出的更改,但我仍然收到 ExpressionChangedAfterItHasBeenCheckedError。
实际情况有点复杂,但这里是代码的简化版本:
https://embed.plnkr.co/sr9k0wLQtyWSATiZuqaK/
提前致谢,这是我关于 Whosebug 的第一个问题:)
我会避免使用在模板内计算高度的方法。相反,我会准备数据以供查看:
<second-cmp
*ngFor="let cmp of generatedData"
[model]="cmp"
[height]="cmp.height"> <------------ already calculated value
然后我会订阅 QueryList.changes
来跟踪生成元素的变化并计算 height
那里:
constructor(
...,
private cdRef: ChangeDetectorRef) {}
ngAfterViewInit() {
this.components.changes.subscribe(components => {
const renderedCmps = components.toArray();
this.generatedData.forEach((x, index) => {
switch (index) {
case 0: // first
x.height = renderedCmps[0].height / 2;
break;
case this.modelData.length: // last
x.height = (renderedCmps[renderedCmps.length - 1].height / 2);
break;
default: // in-between
x.height = (renderedCmps[index - 1].height + renderedCmps[index].height) / 2
}
});
this.cdRef.detectChanges();
});
}
+ 'px'
是多余的,因为我们可以在样式绑定中指定它:
[style.height.px]="height"
反应非常好@yurzui,效果很好!
在模型数据上设置高度 属性 也消除了单独绑定它的必要性,因为我已经将整个模型的引用传递给 *ngFor 中的组件。
<second-cmp
*ngFor="let cmp of generatedData"
[model]="cmp"> <!-- the height doesn't need to be binded separately anymore -->
@Component({
selector: 'second-cmp',
template: `
<li>
<div class="item" [style.height.px]="model.height">Calculated height</div>
</li>`
)}
export class Second {
@Input('model') model;
// @Input('height') height; <-- removed
}