angular - 在 *ngIf 中加载动态组件 - createComponent 未定义

标签 angular angular8 angular-ng-if

当用户单击如下所示的按钮时,我正在尝试将动态组件加载到我的 View 中:

<button (click)="showContent()">Show Panel</button>
<!--This starts as 'showPanel = false'-->
<div *ngIf="showPanel">
    <ng-template #ref></ng-template>
</div>

但是,当单击我 View 中的按钮时,我尝试运行 loadComponent()但我收到一条错误消息 Cannot read property 'createComponent' of undefined

我已经查找了一些解决方案,有人建议使用 QueryList<ViewContainerRef>但我没有成功让它发挥作用。

Source: ViewContainerRef is undefined when called in ngAfterViewInit

另一种解决方案建议使用 ElementRef并检查已更改的状态,但即使在尝试检查它时也始终未定义 ngAfterViewInit .

Source: @ViewChild in *ngIf

我正在寻找适用于 Angular 8 的选项,但我不完全确定下一步该去哪里。

代码如下:

parent.component.ts

export class ParentComponent {

@ViewChild('ref', { static: false, read: ViewContainerRef }) ref: ViewContainerRef;

showPanel = false;

loadComponent(): void {
    const factory = this.componentFactoryResolver.resolveComponentFactory(ChildComponent);
    const component = this.ref.createComponent(factory);
    component.changeDetectorRef.detectChanges();
}

showContent(): void {
    this.showPanel = !this.showPanel;
    this.loadContent(); // Error is thrown here, this doesn't make sense as *ngIf should now be true.
}

最佳答案

按照 yurzui 的想法,下面是我将如何应用它们:

Here是 StackBlitz 示例

changeDetectorRef.detectChanges()

showContent () {
    this.showPanel = !this.showPanel;

   if (this.showPanel) {
      this.cdr.detectChanges();
      this.loadComponent();
    }
  }

ViewChild 的 setter

  private _ref: ViewContainerRef;

  private get ref () {
    return this._ref;
  }

  @ViewChild('ref', { static: false, read: ViewContainerRef })
  private set ref (r) {
    console.log('setting ref', r)
    this._ref = r;

    if (this._ref) {
      this.loadComponent();
    }
  }

  showPanel = false;

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

  loadComponent () {
    const factory = this.cfr.resolveComponentFactory(ChildComponent);
    const component = this.ref.createComponent(factory);
  }

  showContent () {
    this.showPanel = !this.showPanel;
  }

使用<ng-container>

正如您所指出的,使用 ngTemplateOutlet通常是一个很好的解决方案,但是当您处理多个组件时,在模板中执行所有这些逻辑会变得很麻烦。

我们可以利用 ViewContainerRef 's用于处理组件中所有内容的 API ( .ts file)。

<button (click)="showContent()">Show Panel</button>

<ng-container #vcr></ng-container>
@ViewChild('vcr', { static: true, read: ViewContainerRef })
 vcr: ViewContainerRef;

 showContent () {
  this.showPanel = !this.showPanel;  

  this.showPanel && this.attachComponent();

  !this.showPanel && this.removeComponent();  
}

private attachComponent () {
  const compFactory = this.cfr.resolveComponentFactory(ChildComponent);

  const compView = this.vcr.createComponent(compFactory);
}

private removeComponent () {
    this.vcr.clear();
}

这种方法给了你更多的控制权!
例如,您可以在 showPanel 之后保留组件的状态。使用 vcr.detach 变为假和 vcr.insert .

You can find how right here .

关于angular - 在 *ngIf 中加载动态组件 - createComponent 未定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58646928/

相关文章:

javascript - 基本 Angular 组件未在浏览器中显示

angular - 使用 *ngIf Angular2 隐藏/显示

angular - 如何手动重新渲染组件?

angular - 如何在 angular-cli 中的 environment.ts 中注入(inject)提交哈希

Angular 组件,它是将被添加到另一个表中的两行

angular - 别名已被 "--collection"选项使用,不能被 "--change-detection"选项使用

来自 Github 的 Angular 模块,如何集成到我的模块中?

javascript - 使用 Angular 天数中的两个日期之间的差异

angular - *ngIf 语句中 else 部分不执行

html - 嵌套 *ngFor* 与 *ngIf