如何注入动态创建组件的服务

时间:2018-03-20 14:08:43

标签: angular

export interface InfoPanelComponent {
    data: any;
}

export class ComplaintsComponent implements OnInit, InfoPanelComponent {
   data: any;             
   constructor(private navigationService: NavigationService, private activatedRoute: ActivatedRoute) {
   }

  onCancelClicked() {
      console.log(this.navigationService);
      this.navigationService.hidePanel(this.data.key, this.activatedRoute);
  }
}

问题是,this.navigationService未定义。服务本身在app.modules.ts中提供,可以成功注入其他组件。

我认为它不起作用的原因是上面的组件(以及将来的更多组件)是动态创建的:

private addPanel(item: InfoPanelItem, itemKey: string): void {
      const componentFactory = this.componentFactoryResolver.resolveComponentFactory(item.component);
      const viewContainerRef = this.infopanelHost.viewContainerRef;

      // create new component
      const componentRef = viewContainerRef.createComponent(componentFactory);

      (<InfoPanelComponent>componentRef.instance).data = item.data;   
  }

我认为这些服务没有被注入。有没有办法一般地注入该组件所需的所有依赖项?请注意,ComplaintsComponent只是一个示例,还有更多内容,可能需要不同的服务。

1 个答案:

答案 0 :(得分:2)

您可以通过以下两种方式为动态组件提供服务。在我的示例中,我将演示在容器组件DynamicContainerComponent中创建组件。

首先在容器组件中导入您需要的所有服务。在我的示例中AExampleServiceBExampleService

<强> DynamicContainerComponent

import {
  Component, ViewChild, AfterContentInit, ComponentFactoryResolver, Compiler, ViewContainerRef, NgModule, NgModuleRef,
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AExampleService } from './services/AExampleService';
import { BExampleService } from './services/BExampleService';


@Component({
  selector: 'dynamic-container',
  template: `<ng-container #vc></ng-container>`,
  styleUrls: ['./dynamic-container.component.css']
})
export class DynamicContainerComponent implements AfterContentInit{
  @ViewChild('vc', { read: ViewContainerRef }) _container: ViewContainerRef;

  constructor(private aExampleService: AExampleService) { }

  ngAfterContentInit(){
    this.addDynamicComponent();
  }

  private addDynamicComponent(): void{...}
}

现在,您可以在动态组件中使用依赖项注入来使用AExampleServiceBExampleService。此示例显示了两种方法:

  • 将服务BExampleService直接DI到动态组件
  • 将父组件DynamicContainerComponent注入将公开AExampleService动态组件

查看private addDynamicComponent(): void{...}

中的代码

<强> addDynamicComponent()

private addDynamicComponent(): void{

  @Component({
    template: `<h2>This is a dynamic component</h2>`,
    styleUrls: ['./dynamic.component.css']
  })
  class DynamicComponent {
    constructor(
      public _parent: DynamicContainerComponent,
      private bExampleService: BExampleService) { }

    private someFunctionA(): void {
      this._parent.aExampleService.doSomthingA();
    }

    private someFunctionB(): void {
      this.bExampleService.doSomthingB();
    }
  }
  @NgModule({
    imports: [
      BrowserModule
    ],
    declarations: [DynamicComponent],
  }) class DynamicModule { }

  const mod = this.compiler.compileModuleAndAllComponentsSync(DynamicModule);
  const factory = mod.componentFactories.find((comp) =>
    comp.componentType === DynamicComponent
  );

  this.cmpRef = this._container.createComponent(factory);
}

请注意,AExampleServiceBExampleService都未被声明为动态组件的提供者,而是被声明为包含DynamicContainerComponent的模块的提供者