Angular-添加动态组件时发生异常 [英] Angular - Exception when adding dynamic component
问题描述
我有一个简单的测试代码,用于使用Angular 4添加动态组件.
I have a simple test code for adding dynamic components with 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)
}
}
所有这些代码所做的就是在末尾添加一个虚拟模板.
All this code is doing is adding a dummy template at the end.
但是此代码引发异常:
ExpressionChangedAfterItHasBeenCheckedError:表达式已更改经过检查后.上一个值:未定义".当前值: ''.似乎该视图是在其父级和孩子们已经脏了检查.是否已在更改中创建检测钩?
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 ?
这是描述性很好的例外.在检查更改后,视图已更新.
It is well descriptive exception. A view has been updated after already checked for changing.
但是我在这里有些不明白的地方:
But there are few things which I don't understand here :
问题:
1:
如果我从模板中删除了 input
,那么现在的模板是:
If I remove the input
from the template - so now the template is :
<ng-template #template>
<li></li>
</ng-template>
-那么我没有例外.为什么会这样?
— Then I don't get an exception. Why is that ?
2:
另一种解决方案是将 ngAfterViewInit
替换为 ngAfterContentInit
.我已经知道两者之间的区别.
Another solution(among many) is to replace ngAfterViewInit
with ngAfterContentInit
. I already know the difference between those two.
如果是这样-我可以得出结论(发生异常的事实)在每个Angualr事件中-都发生了更改检测?(这很有意义,因为 ngAfterViewInit
发生_after_ ngAfterContentInit
),所以Angular可能已经检测到 ngAfterViewInit
中的上一个动态变化.?我说的对吗?
If so - can I conclude ( from the fact that the exception is gone) that at each Angualr's event - a change detection is occurred? (which make sense becuase ngAfterViewInit
happens _after_ ngAfterContentInit
) , so maybe Angular has detected the prev dynamic change in ngAfterViewInit
? Am I right?
推荐答案
如果我从模板中删除输入-现在模板是:
If I remove the input from the template - so now the template is :
输入未引起问题. ngModel
指令会导致问题.指令和组件实例表示为angular内的视图节点-当前组件的子级.在每个变更检测周期内,Angular会更新这些组件/指令实例的输入.以下摘录自您需要了解的有关Angular变更检测的所有信息,其中显示了操作顺序:
The input is not causing the problem. ngModel
directive causes a problem. Directives and components instances are represented as view nodes inside angular - sort of children of the current component. During each change detection cycle, Angular updates inputs for these component/directive instances. Here is the excerpt from the Everything you need to know about change detection in Angular that shows the order of operations:
- 更新子组件/指令实例(1)上的 input 属性
- 在子组件/指令实例上调用 AfterContentInit 和AfterContentChecked生命周期挂钩(5)
- 运行子视图的更改检测(重复此列表中的步骤)(8)
- 在子组件/指令实例上调用 AfterViewInit 和AfterViewChecked生命周期挂钩(9)
- 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进行更改检测.它为 _Component
(6)运行更改检测.尚无指令,因此无需检查.然后,Angular调用 _Component
的 afterViewInit
钩子,在其中创建子指令实例 ngModel
.但是,从未触发指令 ngModel
的更改检测!当前的更改检测周期结束后,Angular检查更改,并发现 ngModel
的 @Input
是空字符串,但先前的值是 undefined
,因为它从未被检查过.
So assume that Angular is doing change detection for the AppComponent. It runs change detection for the _Component
(6). There are no directives yet so nothing to check. Then Angular calls afterViewInit
hook for the _Component
, where you create a child directive instance ngModel
. But the change detection for the directive ngModel
is never triggered! After the current change detection cycle is finished, Angular checks for changes and finds that @Input
of ngModel
is an empty string, but the previous values is undefined
since it was never checked.
与使用 AfterContentInit
挂钩的情况进行比较.挂接到 _Component
的角度调用.您在此处创建一个子指令.Angular运行 _Component
的更改检测.现在,该指令已经存在,因此也将对此子指令运行更改检测,作为 _Component
的更改检测的一部分.由于Angular应用了空字符串初始值,因此下次检查该指令时不会发生错误.
Compare that with the case when you used AfterContentInit
hook. Angular calls that hook for _Component
. You create a child directive there. Angular runs change detection for the _Component
. Now, the directive already exists so change detection is also run for this child directive as part of change detection for the _Component
. Since Angular applied empty string initial value, no error occurs next time the directive is checked.
这篇关于Angular-添加动态组件时发生异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!