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 中的上一个动态变化?我说得对吗?

PLNKR

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应用了空字符串初始值,下次检查指令时不会出错。