Angular - 添加动态组件时出现异常
Angular - Exception when adding dynamic component
我有一个简单的测试代码,用于添加动态组件 Angular 4.
@Component({
selector: 'component',
template: `
<ul><li #item *ngFor="let number of list">{{number}}</li></ul>
<ng-template #anchor> </ng-template>
<ng-template #template>
<li><input type="text" [(ngModel)]="myInput"/></li>
</ng-template>`
})
class _Component {
@ViewChild('template')
template: TemplateRef<any>
@ViewChild('anchor', { read: ViewContainerRef })
anchor: TemplateRef<any>
@ViewChildren('item', { read: ViewContainerRef })
items: QueryList<ViewContainerRef>
myInput='';
list: number[] = [0, 1, 2, 3, 4]
ngAfterViewInit() {
this.anchor.createEmbeddedView(this.template)
}
}
这段代码所做的只是在末尾添加一个虚拟模板。
但是此代码抛出异常:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed
after it was checked. Previous value: 'undefined'. Current value: ''.
It seems like the view has been created after its parent and its
children have been dirty checked. Has it been created in a change
detection hook ?
这是一个很好的描述性异常。已检查更改后已更新视图。
但是这里有一些我不明白的地方:
问题:
1:
如果我从模板中删除 input
- 那么现在的模板是:
<ng-template #template>
<li></li>
</ng-template>
— 那我没有得到异常。这是为什么?
2:
另一个解决方案(在许多解决方案中)是用 ngAfterContentInit
替换 ngAfterViewInit
。我已经知道这两者之间的区别。
如果是这样 - 我可以得出结论(从异常消失的事实)在每个 Angualr 的事件中 - 发生变化检测? (这是有道理的,因为 ngAfterViewInit
发生在 _after_ ngAfterContentInit
),所以也许 Angular 检测到 ngAfterViewInit
中的上一个动态变化?我说得对吗?
If I remove the input from the template - so now the template is :
输入不是导致问题的原因。 ngModel
指令导致问题。指令和组件实例表示为 angular 内的视图节点 - 当前组件的子类。在每个变更检测周期中,Angular 更新这些 component/directive 个实例的输入。以下是显示操作顺序的 Everything you need to know about change detection in Angular 的摘录:
- updates input properties on a child component/directive instances (1)
- calls AfterContentInit and AfterContentChecked lifecycle hooks on child component/directive instances (5)
- runs change detection for a child view (repeats the steps in this list) (8)
- calls AfterViewInit and AfterViewChecked lifecycle hooks on child component/directive instances (9)
因此假设 Angular 正在对 AppComponent 进行更改检测。它 运行s 更改检测 _Component
(6)。目前还没有指令,所以没有什么可检查的。然后 Angular 为 _Component
调用 afterViewInit
挂钩,您在其中创建子指令实例 ngModel
。但是从未触发指令 ngModel
的变化检测!当前变化检测循环结束后,Angular检查变化,发现ngModel
的@Input
是空串,但之前的值是undefined
,因为从来没有检查。
将其与使用 AfterContentInit
钩子时的情况进行比较。 Angular 为 _Component
调用该挂钩。您在那里创建一个子指令。 Angular 运行 对 _Component
的更改检测。现在,该指令已经存在,因此作为 _Component
的变化检测的一部分,此子指令的变化检测也是 运行。由于Angular应用了空字符串初始值,下次检查指令时不会出错。
我有一个简单的测试代码,用于添加动态组件 Angular 4.
@Component({
selector: 'component',
template: `
<ul><li #item *ngFor="let number of list">{{number}}</li></ul>
<ng-template #anchor> </ng-template>
<ng-template #template>
<li><input type="text" [(ngModel)]="myInput"/></li>
</ng-template>`
})
class _Component {
@ViewChild('template')
template: TemplateRef<any>
@ViewChild('anchor', { read: ViewContainerRef })
anchor: TemplateRef<any>
@ViewChildren('item', { read: ViewContainerRef })
items: QueryList<ViewContainerRef>
myInput='';
list: number[] = [0, 1, 2, 3, 4]
ngAfterViewInit() {
this.anchor.createEmbeddedView(this.template)
}
}
这段代码所做的只是在末尾添加一个虚拟模板。
但是此代码抛出异常:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: ''. It seems like the view has been created after its parent and its children have been dirty checked. Has it been created in a change detection hook ?
这是一个很好的描述性异常。已检查更改后已更新视图。
但是这里有一些我不明白的地方:
问题:
1:
如果我从模板中删除 input
- 那么现在的模板是:
<ng-template #template>
<li></li>
</ng-template>
— 那我没有得到异常。这是为什么?
2:
另一个解决方案(在许多解决方案中)是用 ngAfterContentInit
替换 ngAfterViewInit
。我已经知道这两者之间的区别。
如果是这样 - 我可以得出结论(从异常消失的事实)在每个 Angualr 的事件中 - 发生变化检测? (这是有道理的,因为 ngAfterViewInit
发生在 _after_ ngAfterContentInit
),所以也许 Angular 检测到 ngAfterViewInit
中的上一个动态变化?我说得对吗?
If I remove the input from the template - so now the template is :
输入不是导致问题的原因。 ngModel
指令导致问题。指令和组件实例表示为 angular 内的视图节点 - 当前组件的子类。在每个变更检测周期中,Angular 更新这些 component/directive 个实例的输入。以下是显示操作顺序的 Everything you need to know about change detection in Angular 的摘录:
- updates input properties on a child component/directive instances (1)
- calls AfterContentInit and AfterContentChecked lifecycle hooks on child component/directive instances (5)
- runs change detection for a child view (repeats the steps in this list) (8)
- calls AfterViewInit and AfterViewChecked lifecycle hooks on child component/directive instances (9)
因此假设 Angular 正在对 AppComponent 进行更改检测。它 运行s 更改检测 _Component
(6)。目前还没有指令,所以没有什么可检查的。然后 Angular 为 _Component
调用 afterViewInit
挂钩,您在其中创建子指令实例 ngModel
。但是从未触发指令 ngModel
的变化检测!当前变化检测循环结束后,Angular检查变化,发现ngModel
的@Input
是空串,但之前的值是undefined
,因为从来没有检查。
将其与使用 AfterContentInit
钩子时的情况进行比较。 Angular 为 _Component
调用该挂钩。您在那里创建一个子指令。 Angular 运行 对 _Component
的更改检测。现在,该指令已经存在,因此作为 _Component
的变化检测的一部分,此子指令的变化检测也是 运行。由于Angular应用了空字符串初始值,下次检查指令时不会出错。