Angular Dynamic Component Injection error

女生的网名这么多〃 提交于 2019-12-10 15:49:17

问题


I'm building a small reference application to see how to dynamically inject components in one component to view the content on the page. I'm getting an error that points to the ViewContainerRef object.

This is the component that should display the injected component's content in the view, but it's throwing an error:

Here is the StatsComponent that is throwing the error:

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;
  }

}

I have a working demo here, and a github project.

Why is the container not being referenced?

[UPDATE]: this now works! Go to my demo and github project to see it in action.


回答1:


Angular can't recognize @ViewChild(ComponentHostDirective) in your template because you didn't include ComponentHostDirective directive to list of directives that are used to compile StatsComponent:

To understand which directives angular uses to compile angular template take a look at this answer Angular 2 Use component from another module (see diagram)

I know you have already declared ComponentHostDirective within AppModule. But your StatsComponent is declared within HomeModule and this module knows nothing about ComponentHostDirective. We have to declare or import this directive in HomeModule.

If we will declare ComponentHostDirective in HomeModule we get the error

Type ComponentHostDirective is part of the declarations of 2 modules: AppModule and HomeModule!

SharedModule comes to the rescue:

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 { }

After that your appComponentHost property will refer to ComponentHostDirective instance.

In addition, you will get the error

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'Customers'.

after component creation.

Don't change bindings within ngAfterViewInit hook. Use ngOnInit instead:

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

The article Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains the behavior in great details (Thank's @Maximus).

Finally you will see the result:




回答2:


small buglet:

this.componentRef = viewContainerRef.createComponent(componentFactory);

should be:

let componentRef = viewContainerRef.createComponent(componentFactory);

don't add it on the component. and use let instead of const.



来源:https://stackoverflow.com/questions/45516705/angular-dynamic-component-injection-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!