【问题标题】:Angular Dynamic Component Injection errorAngular 动态组件注入错误
【发布时间】:2018-01-12 23:26:43
【问题描述】:

我正在构建一个小型参考应用程序,以了解如何在一个组件中动态注入组件以查看页面上的内容。我收到指向 ViewContainerRef 对象的错误。

这是应该在视图中显示注入组件内容的组件,但它会抛出错误:

这是引发错误的 StatsComponent:

export class StatsComponent implements AfterViewInit, OnDestroy {
  @Input() dynComp: DynamicComponent;
  @ViewChild(ComponentHostDirective) appComponentHost: ComponentHostDirective;
  componentRef: ComponentRef<any>;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  ngAfterViewInit() {
    this.loadComponent();
  }

  ngOnDestroy() {
    this.componentRef.destroy();
  }

  loadComponent() {
    console.log('inside stats component: ', this.dynComp);
    const comp = this.dynComp;
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(comp.component);
    console.log('host: ', this.appComponentHost);  // <-- this is undefined

    const viewContainerRef = this.appComponentHost.viewContainerRef;
    viewContainerRef.clear();

    this.componentRef = viewContainerRef.createComponent(componentFactory);
    (<DynamicComponent>this.componentRef.instance).data = comp.data;
  }

}

我有一个工作演示 here 和一个 github 项目。

为什么容器没有被引用?

[更新]:现在可以了!转到我的演示和 github 项目,看看它的实际效果。

【问题讨论】:

  • 可能是因为&lt;ng-template&gt;。尝试使用&lt;div&gt; 作为测试。

标签: angular dynamic components


【解决方案1】:

小号:

this.componentRef = viewContainerRef.createComponent(componentFactory);

应该是:

let componentRef = viewContainerRef.createComponent(componentFactory);

不要在组件上添加它。并使用 let 代替 const。

【讨论】:

    【解决方案2】:

    Angular 无法识别模板中的 @ViewChild(ComponentHostDirective),因为您没有将 ComponentHostDirective 指令包含到用于编译 StatsComponent 的指令列表中:

    要了解 Angular 使用哪些指令来编译 Angular 模板,请查看此答案 Angular 2 Use component from another module(见图)

    我知道你已经在AppModule 中声明了ComponentHostDirective。但是你的StatsComponent 是在HomeModule 中声明的,而这个模块对ComponentHostDirective 一无所知。 我们必须在HomeModule 中声明或导入此指令

    如果我们在HomeModule 中声明ComponentHostDirective,则会出现错误

    类型 ComponentHostDirective 是 2 个模块声明的一部分: AppModule 和 HomeModule!

    SharedModule 来救援:

    src/app/shared/shared.module.ts

    @NgModule({
      imports: [
        CommonModule
      ],
      declarations: [
        ComponentHostDirective
      ],
      exports: [
        CommonModule,
        ComponentHostDirective
      ]
    })
    export class SharedModule {}
    

    app.module.ts

    @NgModule({
      declarations: [
        ComponentHostDirective <== remove it
      ],
      imports: [
        ...
        SharedModule, // add this
        ...
      ]
    })
    export class AppModule { }
    

    home.module.ts

    @NgModule({
      imports: [
        ...
        SharedModule, // add this
        ...
      ]
    })
    export class HomeModule { }
    

    之后,您的 appComponentHost 属性将引用 ComponentHostDirective 实例。

    另外,你会得到错误

    ExpressionChangedAfterItHasBeenCheckedError:表达式已更改 检查后。以前的值:'未定义'。当前值: '客户'。

    在组件创建之后。

    不要更改 ngAfterViewInit 挂钩内的绑定。请改用ngOnInit

    export class StatsComponent implements OnInit, OnDestroy {
      ...
      ngOnInit() {
        this.loadComponent();
      }
    

    文章Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error 详细解释了该行为(感谢@Maximus)。

    最后你会看到结果:

    【讨论】:

    • 太棒了!这行得通,现在,有点。现在唯一的问题是它应该显示任何被选中的按钮的内容,而不仅仅是第一个。所以我仍然缺少一些东西。并感谢您对各种文章的引用。信息量很大。要完全理解它们需要阅读一些内容。
    • @KingWilder 只需将ngOnInit 更改为ngOnChanges
    • 是的,做到了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 2018-07-21
    相关资源
    最近更新 更多