【问题标题】:Dynamically create a component inside an ngIf在 ngIf 中动态创建组件
【发布时间】:2018-06-11 01:32:35
【问题描述】:

我正在使用 Angular 6,我已经尝试按照答案 here 进行操作,但我无法让它工作

export class AppComponent implements AfterContentInit, AfterViewInit {
  defaultToTrue = true;
  @ViewChildren('parent', { read: ViewContainerRef }) parent: QueryList<ViewContainerRef>;

  constructor(private cfr: ComponentFactoryResolver) { }

  ngAfterViewInit(){
    const resolve = this.cfr.resolveComponentFactory(ChildComponent);
    this.parent.changes.subscribe(changes => {
      this.parent.createComponent(resolve); //Error
    });
  }

}

HTML:

<div *ngIf="defaultToTrue">
  <div #parent></div>
</div>

StackBlitz

【问题讨论】:

  • @yurzui 谢谢,但问题是我收到“检查错误后表达式已更改”。但是我在 stackblitz 上没有看到这个。
  • 好的,我删除了我的答案,因为它是错误的。您必须自己确定您的应用是否曾进入 AfterViewInit。但请记住我在下面所说的:在您的订阅中,parent 仍然是QueryList&lt;ViewContainerRef&gt; 类型的列表。这个列表没有与普通 ViewContainerRef 相同的方法。你不能在这里使用this.parent.createComponent(resolve);。尽管我对解决方案的建议没有奏效,但这仍然是正确的。
  • @yurzui 的建议有效吗(尽管有例外)?
  • 所以你只需要摆脱异常?这两种技术之一可能会有所帮助:(1)在createComponent 之后调用ChangeDetectorRef.detectChanges(); (2) 与setTimeout(() =&gt; { this.parent.createComponent(resolve); })异步调用createComponent

标签: angular


【解决方案1】:

要摆脱ExpressionChangedAfterItHasBeenCheckedError,您可以使用this Angular In Depth blog post 中建议的技术之一:

使用ChangeDetectorRef.detectChanges进行强制变化检测

constructor(private cfr: ComponentFactoryResolver, private cd: ChangeDetectorRef) { }

ngAfterViewInit(){
  const resolve = this.cfr.resolveComponentFactory(ChildComponent);
  this.parent.changes.subscribe(changes => {
    this.parent.createComponent(resolve);
    this.cd.detectChanges();  // Trigger change detection
  });
}

使用setTimeout异步创建组件

ngAfterViewInit(){
  const resolve = this.cfr.resolveComponentFactory(ChildComponent);
  this.parent.changes.subscribe(changes => {
    setTimeout(() => { this.parent.createComponent(resolve); });
  });
}

【讨论】:

    【解决方案2】:

    我的情况是 #container 在 2 个 *ngFor 内,而所有这些都在 *ngIf

    我什至可以获得ViewContainerRefQueryList&lt;ViewContainerRef&gt; 实例的唯一方法是在ngAfterViewChecked 中,并且只能在一个条件内,甚至是与setTimeout 一起运行的条件

    编辑:必须添加一个标志才能停止,否则它会无休止地运行

    if (this.fieldsContainer && this.componentsGenerated == false) {
      this.componentsGenerated = true
      setTimeout(this.generateComponents.bind(this))
    }
    

    编辑2: 最后需要更多的代码来处理所有这些并使用changeDetection: ChangeDetectionStrategy.OnPushcd:ChangeDetectorRef

    ngAfterViewChecked(): void {
    
      if (this.fieldsContainersQuery && this.componentsGenerated == false) {
        this.componentsGenerated = true
    
        this.fieldsContainersQuery.changes.subscribe(changes=>{
          this.fieldsContainersQuery.forEach(fieldContainerItem => this.generateComponents(fieldContainerItem))
          this.cd.detectChanges()
       })
     }
    

    更多细节

    blog github

    【讨论】:

      猜你喜欢
      • 2017-04-10
      • 2018-08-30
      • 2020-02-27
      • 1970-01-01
      • 2021-07-27
      • 2011-03-01
      • 2017-07-07
      • 1970-01-01
      • 2018-12-17
      相关资源
      最近更新 更多