angular - ng2: creación dinámica de un componente basado en una plantilla
angular2-components angular2-injection (2)
También es posible iterar a través de la importación :
import * as possibleComponents from ''./someComponentLocation''
...
let inputComponent;
for(var key in possibleComponents ){
if(key == componentStringName){
inputComponent = possibleComponents[key];
break;
}
}
Actualización: o simplemente :-)
let inputComponent = possibleComponents[componentStringName]
entonces puede crear una instancia del componente, por ejemplo:
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);
}
tenga en cuenta que el componente debe estar en @NgModule entryComponents
He estado mirando las API de Angular 2 para
ComponentResolver
y
DynamicComponentResolver
para crear componentes dinámicos, pero tengo en mente algo diferente de lo que ofrecen esas API.
¿Hay alguna forma en NG2 para crear un componente basado en una cadena de su nombre de clase?
Por ejemplo, estoy construyendo un tablero de gráficos configurable. El diseño de cada usuario se almacena en la base de datos, indicando que quieren 2x gráficos de líneas aquí, 3x gráficos de barras allí, etc.
Cuando cargo estos datos como json, se ve algo así como:
user.charts = [
{ type: ''LineChartComponent'', position: ... }
{ type: ''BarChartComponent'', position: ... }
];
Donde
type
es el nombre de clase del componente que quiero crear reflexivamente.
Hasta ahora tengo lo siguiente:
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);
Pero la idea es eliminar la necesidad de
chartMap
.
¿Cómo puedo crear reflexivamente esta clase basada en una cadena sin tener una referencia al tipo?
Actualización2:
Como @estus mencionó en la versión de comentarios con className no funcionará con minificación. Para hacerlo trabajando con minificación puedes
1) agregue alguna clave estática en cada uno de sus
entryComponents
como:
export LineChartComponent {
static key = "LineChartComponent";
}
y luego use esta
key
como única.
const factoryClass = <Type<any>>factories.find((x: any) => x.key === compClassKey);
2) crear diccionario como
export const entryComponentsMap = {
''comp1'': Component1,
''comp2'': Component2,
''comp3'': Component3
};
y entonces
const factory = this.resolver.resolveComponentFactory(entryComponentsMap.comp1);
Actualización1:
Aquí está la versión del nombre de la clase del componente
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);
Versión antigua
Puede obtener la fábrica mediante el selector de componentes, pero debe usar la propiedad privada.
Puede verse algo así como:
const factories = Array.from(this.resolver[''_factories''].values());
const factory = factories.find((x: any) => x.selector === selector);