ng2 - dynamically creating a component based on a template

自闭症网瘾萝莉.ら 提交于 2019-11-26 09:01:55

问题


I\'ve been looking at the Angular 2 APIs for ComponentResolver and DynamicComponentResolver for creating dynamic components, but I have something different in mind than those APIs offer.

Is there any way in NG2 to create a component based on a string of its class name?

For example, Im building a configurable charts dashboard. Each user\'s layout is stored in the database, stating they want 2x line charts here, 3x bar charts there, etc.

When I load this data as json it looks something like:

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

Where type is the component\'s class name that I want to reflectively create.

So far I have the following:

 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);

But the whole idea is to eliminate the need for chartMap. How can I reflectively create this class based on a string without having a reference to the type?


回答1:


Update2:

As @estus mentioned in comments version with className won't work with minification. To do it working with minification you can

1) add some static key on each of your entryComponents like:

export LineChartComponent {
  static key = "LineChartComponent";
}

and then use this key as unique.

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

2) create dictionary like

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

and then

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

Update1:

Here's version from component`s class name

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);
  • How to load component dynamically using component name in angular2?

Old version

You can get factory by component selector but you have to use private property.

It might look something like:

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

Plunker Example




回答2:


It's also possible to iterate through import:

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

Update: or just :-)

let inputComponent = possibleComponents[componentStringName]

then you can create instance of component for example:

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);
}

note that component has to be in @NgModule entryComponents



来源:https://stackoverflow.com/questions/40528592/ng2-dynamically-creating-a-component-based-on-a-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!