【问题标题】:ng2 - dynamically creating a component based on a templateng2 - 基于模板动态创建组件
【发布时间】:2017-03-24 12:57:07
【问题描述】:

我一直在研究用于创建动态组件的 ComponentResolverDynamicComponentResolver 的 Angular 2 API,但我的想法与这些 API 提供的不同。

NG2 中是否有任何方法可以根据其类名字符串创建组件?

例如,我正在构建一个可配置的图表仪表板。每个用户的布局都存储在数据库中,说明他们想要这里 2x 折线图,那里需要 3x 条形图,等等。

当我将此数据加载为 json 时,它看起来像:

user.charts = [
     { type: 'LineChartComponent', position: ... }
     { type: 'BarChartComponent', position: ... }
];

type 是我想要反射创建的组件的类名。

到目前为止,我有以下内容:

 this.chartMap = {
    'LineChartComponent': LineChartComponent
 };

let config = this.configuration;
let chartComponentType = this.chartMap[config.type];
let factory = this.componentFactory.resolveComponentFactory(chartComponentType);
let component = factory.create(this.injector);
component.instance.configuration = config;
this.chartContainer.insert(component.hostView);

但整个想法是消除对chartMap 的需求。如何在不引用类型的情况下基于字符串反射性地创建此类?

【问题讨论】:

    标签: angular angular2-components angular2-injection


    【解决方案1】:

    更新2:

    正如@estus 在带有 className 的 cmets 版本中提到的那样,它不适用于缩小。要做到这一点,你可以使用缩小

    1) 在每个 entryComponents 上添加一些静态键,例如:

    export LineChartComponent {
      static key = "LineChartComponent";
    }
    

    然后将此key 用作唯一。

    const factoryClass = <Type<any>>factories.find((x: any) => x.key === compClassKey);
    

    2) 创建一个类似的字典

    export const entryComponentsMap = {
      'comp1': Component1,
      'comp2': Component2,
      'comp3': Component3
    };
    

    然后

    const factory = this.resolver.resolveComponentFactory(entryComponentsMap.comp1);
    

    更新1:

    这是组件类名的版本

    const factories = Array.from(this.resolver['_factories'].keys());
    const factoryClass = <Type<any>>factories.find((x: any) => x.name === compClassName);
    const factory = this.resolver.resolveComponentFactory(factoryClass);
    

    旧版本

    您可以通过组件选择器获取工厂,但您必须使用私有属性。

    它可能看起来像:

    const factories = Array.from(this.resolver['_factories'].values());
    const factory = factories.find((x: any) => x.selector === selector);
    

    Plunker Example

    【讨论】:

    • 谢谢,但这种方法对我来说似乎很脆弱。如果组件工厂注册表没有被 Angular 公开,我宁愿使用类名而不是选择器。然后问题就变成了 Typescript 问题,而不是 Angular 问题。即如何使用字符串“MyComponent”来实例化类型MyComponent
    • 这不适用于缩小,答案至少应该提到这一点。
    【解决方案2】:

    也可以遍历import

    import * as possibleComponents from './someComponentLocation'
    ...
    let inputComponent;
    for(var key in possibleComponents ){
          if(key == componentStringName){
              inputComponent = possibleComponents[key];
              break;
          }
     }
    

    更新:或只是:-)

    let inputComponent = possibleComponents[componentStringName]
    

    然后您可以创建组件实例,例如:

    if (inputComponent) {
        let inputs = {model: model};
        let inputProviders = Object.keys(inputs).map((inputName) => { return { provide: inputName, useValue: inputs[inputName] }; });
        let resolvedInputs = ReflectiveInjector.resolve(inputProviders);
        let injector: ReflectiveInjector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicInsert.parentInjector);
        let factory = this.resolver.resolveComponentFactory(inputComponent as any);
        let component = factory.create(injector);
        this.dynamicInsert.insert(component.hostView);
    }
    

    注意组件必须在@NgModule entryComponents中

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-16
      • 2021-09-14
      • 2013-03-26
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 2018-11-14
      • 2019-06-24
      相关资源
      最近更新 更多