10

我一直在研究用于创建动态组件的 Angular 2 API ComponentResolverDynamicComponentResolver但我的想法与那些 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. 如何在不引用类型的情况下基于字符串反射性地创建此类?

4

2 回答 2

22

更新2:

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

entryComponents1)在你喜欢的每一个上添加一些静态键:

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 示例

于 2016-11-17T18:26:03.957 回答
3

也可以遍历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

于 2017-11-07T12:12:14.653 回答