angular angular2-components angular2-injection

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

Ejemplo de Plunker