Vla*_*yev 2 javascript exception angular
我有选项卡和选项卡组件:
tabs.component.ts:
@Component({
selector: 'cl-tabs',
template: `<ng-content></ng-content>`,
styleUrls: ['tabs.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TabsComponent implements AfterContentInit {
@ContentChildren(TabComponent) tabs: QueryList<TabComponent>;
ngAfterContentInit(): void {
if (0 < this.tabs.length) {
this.activate(this.tabs.first);
}
}
activate(activatedTab: TabComponent) {
this.tabs.forEach(tab => tab.active = false);
activatedTab.active = true;
}
}
Run Code Online (Sandbox Code Playgroud)
tab.component.ts:
@Component({
selector: 'cl-tab',
template: `<ng-content></ng-content>`,
styleUrls: ['tab.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TabComponent {
@Input() title: string;
@Input() @HostBinding('class.is-active') active: boolean = false;
}
Run Code Online (Sandbox Code Playgroud)
app.component.html:
<cl-tabs>
<cl-tab *ngFor="let item of items" [title]="item.name">
<any-component [item]="item"></any-component>
</cl-tab>
</tabs>
Run Code Online (Sandbox Code Playgroud)
当使用 *ngFor 创建选项卡时,会抛出 ExpressionChangedAfterItHasBeenCheckedError。
cdRef.detectChanges(),正如在许多情况下所建议的,没有帮助。
如果出现以下情况,错误就会消失:
为什么在前两种情况下错误会消失?在这种特殊情况下,有没有更好的 setTimeout 替代方案?
更新:在 plunker https://embed.plnkr.co/ZUOvf6NXCj2JOLTwbsYU/ 中重现错误
要理解答案,您必须先阅读并理解这两篇文章:
让我们看看下面的App组件模板:
<cl-tabs>
<cl-tab *ngFor="let item of items" [title]="item.name"></cl-tab>
</cl-tabs>
Run Code Online (Sandbox Code Playgroud)
在这里,您有内容投影和嵌入视图(由 创建ngFor)。
有两点是必须理解的:
ngAfterContentInit触发之前检查嵌入的视图。现在,请记住以上几点为您的特定设置
export class App {
items = [
{name: "1", value: 1},
{name: "2", value: 2},
{name: "3", value: 3},
];
}
Run Code Online (Sandbox Code Playgroud)
您可以对 AppComponent 视图的以下结构进行映像:
AppView.nodes: [
clTabsComponentView
ngForEmbeddedViews: [
ngForEmbeddedView<{name: "1", value: 1}>
ngForEmbeddedView<{name: "2", value: 2}>
ngForEmbeddedView<{name: "3", value: 3}>
Run Code Online (Sandbox Code Playgroud)
当为 AppView 触发更改检测时,这里是操作顺序:
1) 检查 clTabsComponentView
2) 检查 ngForEmbeddedViews 中的所有视图。
这里active = false会记住每个视图的值。
3) 调用ngAfterContentInit生命周期钩子。
在这里你更新active = true. 所以在验证阶段 Angular 会检测差异并报告错误。
为什么在前两种情况下错误会消失?现在确定你的意思
statically。如果您的意思是不使用,*ngFor则不会出现错误,因为每个 TabComponentView 将是子视图,而不是嵌入视图。并且在ngAfterContentChecked生命周期钩子之后处理子视图。
如果您删除,@HostBinding则 Angular 将无法检查组件,并且active不会记住值 - 因此不会进行验证和检查。
cdRef.detectChanges(),正如在许多情况下所建议的,没有帮助。
您需要在 AppComponent 上调用更改检测才能使其工作。