angular 4+ assign @Input for ngComponentOutlet dynamically created component

前端 未结 3 1745
渐次进展
渐次进展 2020-11-30 05:54

In Angular 4 to dynamically create a component you can use ngComponentOutlet directive: https://angular.io/docs/ts/latest/api/common/index/NgComponentOutlet-dir

3条回答
  •  执念已碎
    2020-11-30 06:39

    With the help of the post of @Günter Zöchbauer I solved a similar problem this way - I hope you can adapt it somehow.

    First I defined some interfaces:

    // all dynamically loaded components should implement this guy
    export interface IDynamicComponent { Context: object; }
    
    // data from parent to dynLoadedComponent
    export interface IDynamicComponentData {
      component: any;
      context?: object;
      caller?: any;
    }
    

    then I implemented them inside of the dynamically loaded component

    dynamicLoadedComponentA.ts

    // ...
    export class DynamicLoadedComponentA implements IDynamicComponent {
    // ...
    
    // data from parent
    public Context: object;
    
    // ...
    

    After that I built a new component which is responsible for the magic. Important here is that I had to register all dyn. loaded components as entryComponents.

    dynamic.component.ts

    @Component({
      selector: 'ngc-dynamic-component',
      template: ´´,
      entryComponents: [ DynamicLoadedComponentA ]
    })
    export class DynamicComponent implements OnInit, OnDestroy, OnChanges {
      @ViewChild('dynamicContainer', { read: ViewContainerRef }) public dynamicContainer: ViewContainerRef;
    
      @Input() public componentData: IDynamicComponentData;
    
      private componentRef: ComponentRef;
      private componentInstance: IDynamicComponent;
    
      constructor(private resolver: ComponentFactoryResolver) { }
    
      public ngOnInit() {
        this.createComponent();
      }
    
      public ngOnChanges(changes: SimpleChanges) {
        if (changes['componentData']) {
          this.createComponent();
        }
      }
    
      public ngOnDestroy() {
        if (this.componentInstance) {
          this.componentInstance = null;
        }
        if (this.componentRef) {
          this.componentRef.destroy();
        }
      }
    
      private createComponent() {
        this.dynamicContainer.clear();
        if (this.componentData && this.componentData.component) {
          const factory: ComponentFactory = this.resolver.resolveComponentFactory(this.componentData.component);
          this.componentRef = this.dynamicContainer.createComponent(factory);
          this.componentInstance = this.componentRef.instance as IDynamicComponent;
    
          // fill context data
          Object.assign(this.componentInstance.Context, this.componentData.context || {});
    
          // register output events
          // this.componentRef.instance.outputTrigger.subscribe(event => console.log(event));
        }
      }
    }
    

    here the usage of this shiny new stuff:

    app.html

    
    

    app.ts

    // ...
      private _settingsData: IDynamicComponent = {
        component: DynamicLoadedComponentA,
        context: { SomeValue: 42 },
        caller: this
      };
    // ...
    

提交回复
热议问题