网站搜索

angular - 用于生成动态组件的通用函数


我想在我的服务中编写一个函数,用于处理生成动态组件到某个 ViewChild 引用中……

我尽力了

public GenerateDynamicComponent(ComponentName: string,viewContainerRef: ViewContainerRef, data?: any) {   
 switch (ComponentName.toUpperCase()) {
 case 'DYNAMICFORMS':
   const componentFactory = this.resolver.resolveComponentFactory(DynamicFormsComponent);
   const formref = viewContainerRef.createComponent(componentFactory);
   formref.instance.Data = data;
   return formref;
   break;

 default:
  return null;
 }

它确实工作得很好,但我不想使用这个开关并通过字符串发送这个组件名

所以它需要像

 public GenerateDynamicComponent<T>(viewContainerRef: ViewContainerRef,data?: any ) {
 const componentFactory = this.resolver.resolveComponentFactory<T>(typeof T);
 const formref = viewContainerRef.createComponent(componentFactory);
 formref.instance.Data = data;
 return formref;
 }

但是当然这不起作用,因为 typeof T <> 组件类型……是否有可能这样做,还是必须像第一个例子那样?

非常感谢!

答案#1

可以将创建动态组件的通用函数定义如下。

public createDynamicComponent<T>(component: Type<T>, viewRef: ViewContainerRef): ComponentRef<T> {
    const factory = this.cfr.resolveComponentFactory<T>(component);
    return viewRef.createComponent(factory);
  }

并且调用通用函数...

  this.createDynamicComponent<DynamicComponent>(DynamicComponent, this.vc /* ViewContainerRef */);

查看 Stackblitz 示例应用。

注意:确保在模块中将动态组件添加到 entryComponents

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { DynamicComponent } from './dynamic.component';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent, DynamicComponent ],
  entryComponents: [DynamicComponent],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

完整组件上下文

import {
  AfterViewInit, Component, ComponentFactoryResolver, ComponentRef, Type, ViewChild, ViewContainerRef
} from '@angular/core'
import { DynamicComponent } from './dynamic.component'


@Component({
  selector: 'my-app',
  template: `
  <h1>App component</h1>
  <div class="insert-dynamic-component">
    <ng-container #vc></ng-container>
  </div>
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewInit  {
  @ViewChild('vc', {read: ViewContainerRef, static: false}) vc: ViewContainerRef;

  public constructor(private cfr: ComponentFactoryResolver) {}

  ngAfterViewInit() {
    // setTimeout() to prevent error "Expression has changed after it was checked"
    // See: https://blog.angular-university.io/angular-debugging/
    setTimeout(() => {
      const componentRef: ComponentRef<DynamicComponent> =
        this.createDynamicComponent<DynamicComponent>(DynamicComponent, this.vc);
      componentRef.instance.data = 'New data';
    });
  }

  public createDynamicComponent<T>(component: Type<T>, viewRef: ViewContainerRef): ComponentRef<T> {
    const factory = this.cfr.resolveComponentFactory<T>(component);
    return viewRef.createComponent(factory);
  }
}

DynamicComponent

import { Component } from '@angular/core';

@Component({
  selector: 'dynamic-component',
  template: `<h1>Dynamic Component!</h1>
  <p>Data: {{data}}</p>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class DynamicComponent  {
  public data: any
}