使用Angular动态创建组件5

时间:2018-03-30 11:27:55

标签: angular typescript angular5

我一直在使用这样的代码在我的应用程序中动态创建组件。这些组件必须支持动态输入。但现在我尝试更新到Angular 5并且不推荐使用ReflectiveInjector。如果有人知道如何帮助我重复使用Angular 5 ......我将非常感激。

import {Component, Input, ViewContainerRef, ViewChild, ReflectiveInjector, ComponentFactoryResolver} from '@angular/core';
import {
  AComponent,
  BComponent,
  CComponent
} from './';

@Component({
  selector: 'dynamic-component',
  entryComponents: [
    AComponent,
    BComponent,
    CComponent
  ],
  template: `
    <div #dynamicComponentContainer></div>
  `
})
export class DynamicComponent {

  currentComponent = null;

  @ViewChild('dynamicPriceItemComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;

  @Input() set componentData( data: { component: any, inputs: any }) {
    if (!data) {
      return;
    }

    let inputProviders = Object.keys(data.inputs).map((inputName) => {
      return { provide: inputName, useValue: data.inputs[inputName] };
    });

    let resolvedInputs = ReflectiveInjector.resolve(inputProviders);

    let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicPriceItemComponentContainer.parentInjector);

    let factory = this.resolver.resolveComponentFactory(data.component);

    let component = factory.create(injector);

    this.dynamicComponentContainer.insert(component.hostView);

    if (this.currentComponent) {
      this.currentComponent.destroy();
    }

    this.currentComponent = component;
  }

  constructor(private resolver: ComponentFactoryResolver) {

  }
}

3 个答案:

答案 0 :(得分:1)

  

这可以提供一些线索。

constructor(private renderer: Renderer2,
            private viewContainerRef: ViewContainerRef,
            private componentFactoryResolver: ComponentFactoryResolver) {

}

private createdDynamicComponent(): void {
    const factory = this.componentFactoryResolver.resolveComponentFactory(MyComponent);
    const createdComponentComponent = this.viewContainerRef.createComponent(factory);
    this.renderer.appendChild('element where you want append', createdComponentComponent.location.nativeElement);
}

答案 1 :(得分:1)

您需要Injector.create而不是ReflectiveInjector

@Input()
set dynamicContent(dc: { component: any; attribute: any; payload: any }) {
  if (!dc) {
    return;
  }
  const injector = Injector.create({
    providers: [
      {
        provide: dc.attribute,
        useValue: dc.payload
      }
    ],
    parent: this.dynamicComponentContainer.parentInjector
  });
  const factory = this.resolver.resolveComponentFactory(dc.component);
  const component = factory.create(injector);
  this.dynamicComponentContainer.insert(component.hostView);
}

当您在实际动态子组件中注入输入名称时,您当然需要解决Reflection弃用问题。 关键是要避免注入字符串:

constructor(@Inject(LabelComponentAttributes) public ca: LabelComponentAttributes) {
  super();
  this.setCurrentStyles();
  this.setCurrentClasses();
}

将所有输入分组并注入该类。 不要将它们分组到界面中,因为它们仅在运行时以打字稿形式提供。

欢呼声

答案 2 :(得分:0)

将来可能会使用NgComponentOutlet指令。看一下这个issue。同时你可以使用ng-dynamic-component