ng2 - 基于模板动态创建组件
ng2 - dynamically creating a component based on a template
我一直在查看 Angular 2 个用于 ComponentResolver
和 DynamicComponentResolver
的 API 来创建动态组件,但我的想法与那些 API 提供的有所不同。
在 NG2 中是否有任何方法可以根据其 class 名称的字符串创建组件?
例如,我正在构建一个可配置的图表仪表板。每个用户的布局都存储在数据库中,说明他们想要这里 2x 折线图,那里 3x 条形图等。
当我将此数据加载为 json 时,它看起来像:
user.charts = [
{ type: 'LineChartComponent', position: ... }
{ type: 'BarChartComponent', position: ... }
];
其中 type
是我要反射创建的组件的 class 名称。
到目前为止我有以下内容:
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
的需求。如何在不引用类型的情况下基于字符串反射创建此 class ?
更新2:
正如@estus 在带有 className 的评论版本中提到的那样,缩小后将无法使用。要做到这一点,你可以
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:
这是来自组件 class 名称
的版本
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);
也可以遍历 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
我一直在查看 Angular 2 个用于 ComponentResolver
和 DynamicComponentResolver
的 API 来创建动态组件,但我的想法与那些 API 提供的有所不同。
在 NG2 中是否有任何方法可以根据其 class 名称的字符串创建组件?
例如,我正在构建一个可配置的图表仪表板。每个用户的布局都存储在数据库中,说明他们想要这里 2x 折线图,那里 3x 条形图等。
当我将此数据加载为 json 时,它看起来像:
user.charts = [
{ type: 'LineChartComponent', position: ... }
{ type: 'BarChartComponent', position: ... }
];
其中 type
是我要反射创建的组件的 class 名称。
到目前为止我有以下内容:
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
的需求。如何在不引用类型的情况下基于字符串反射创建此 class ?
更新2:
正如@estus 在带有 className 的评论版本中提到的那样,缩小后将无法使用。要做到这一点,你可以
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:
这是来自组件 class 名称
的版本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);
也可以遍历 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