2016-11-10 2 views
7

Я искал API-интерфейс Angular 2 для ComponentResolver и DynamicComponentResolver для создания динамических компонентов, но у меня есть что-то другое в виду, чем предлагаемые API.ng2 - динамическое создание компонента на основе шаблона

Есть ли какой-либо путь в NG2 для создания компонента на основе строки его имени класса?

Например, Im создает настраиваемую панель инструментов диаграмм. расположение каждого пользователя хранится в базе данных, заявляя, что они хотят 2x линейных диаграмм здесь, 3x гистограммы там и т.д.

Когда я загружаю эти данные в формате 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. Как я могу отразить создание этого класса на основе строки без ссылки на этот тип?

ответ

9

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:

Вот версия от имени component`s класса

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

Plunker Example

+0

Спасибо, но такой подход кажется хрупким мне. Если реестр компонентов на основе компонентов не открывается публично, Angular я предпочитаю использовать имя класса, чем селектор. Затем вопрос становится скорее вопросом машинописного текста, чем угловым; то есть, как создать экземпляр типа MyComponent с помощью строки «MyComponent» – parliament

+0

wow, которая была быстрым обновлением, прежде чем я даже прокомментировал LOL. Можете ли вы обновить новую версию plnkr, я думаю, что эта же ссылка для обоих. Вам, вероятно, придется разветвить его – parliament

+0

Я добавил код – yurzui

1

Это также можно перебирать импорта:

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

Update: или просто :-)

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

+0

Хороший ответ спасибо – parliament