2016-11-10 70 views
7

我一直在尋找用於創建動態組件的ComponentResolverDynamicComponentResolver的Angular 2 API,但我有些東西與這些API提供的不同。ng2 - 基於模板動態創建組件

有沒有什麼辦法在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的需要。我如何反思性地創建這個基於字符串的類而不需要引用該類型?

回答

9

UPDATE2:

正如評論版本的className提到不會縮小工作@estus。要做到這一點有微小的工作,你可以

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公開公開,我寧願使用類名稱而不是選擇器。這個問題變得更像是一個Typescript問題而不是一個Angular問題。也就是說,如何在使用字符串「MyComponent」 – parliament

+0

這個快速更新之前實例化MyComponent類型,然後我甚至評論了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; 
     } 
} 

更新:或只是:-)

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