ng2 - динамическое создание компонента на основе шаблона
Я смотрел на API Angular 2 для ComponentResolver
а также DynamicComponentResolver
для создания динамических компонентов, но я имею в виду нечто иное, чем те API, которые предлагают.
Есть ли способ в NG2 создать компонент, основанный на строке его имени класса?
Например, я создаю настраиваемую панель инструментов диаграмм. Разметка каждого пользователя хранится в базе данных, указывая, что им нужны 2х линейные графики здесь, 3х гистограммы там и т. Д.
Когда я загружаю эти данные как 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
, Как я могу рефлексивно создать этот класс на основе строки без ссылки на тип?
2 ответа
Update2:
Как упомянуто в комментариях @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);
Update1:
Вот версия из имени класса компонента
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 * 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