2016-11-10 12 views
7

Przeglądałem interfejsy API Angular 2 dla ComponentResolver i DynamicComponentResolver w celu tworzenia komponentów dynamicznych, ale mam na myśli coś innego niż te interfejsy API.ng2 - dynamiczne tworzenie komponentu opartego na szablonie

Czy jest jakiś sposób w NG2, aby utworzyć komponent na podstawie ciągu jego nazwy klasy?

Na przykład, Im buduje konfigurowalny pulpit wykresów. Układ każdego użytkownika są przechowywane w bazie danych, stwierdzając, że chcą 2x wykresy liniowe tutaj, 3x słupkowe tam itp

Kiedy załadować te dane jako JSON wygląda mniej więcej tak:

user.charts = [ 
    { type: 'LineChartComponent', position: ... } 
    { type: 'BarChartComponent', position: ... } 
]; 

Gdzie type jest nazwa klasy składnika, którą chcę odzwierciedlić.

tej pory mam następujące:

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

Ale cała idea jest wyeliminowanie potrzeby chartMap. Jak mogę odzwierciedlić tę klasę w oparciu o ciąg znaków bez odniesienia do typu?

Odpowiedz

9

Update2:

Jak @estus wymienionych w komentarzach wersji z className nie będzie działać z minifikacji. Aby zrobić to praca z minifikacji można

1) dodać trochę klucza statycznego na każdej z entryComponents jak:

export LineChartComponent { 
    static key = "LineChartComponent"; 
} 

a następnie użyć tego key jako wyjątkową.

const factoryClass = <Type<any>>factories.find((x: any) => x.key === compClassKey); 

2) stworzenie słownika jak

export const entryComponentsMap = { 
    'comp1': Component1, 
    'comp2': Component2, 
    'comp3': Component3 
}; 

a następnie

const factory = this.resolver.resolveComponentFactory(entryComponentsMap.comp1); 

Update1:

Oto wersja z component`s nazwy klasy

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

Stara wersja

Można uzyskać zakładzie przez selektor komponentu ale trzeba użyć własności prywatnej.

To może wyglądać:

const factories = Array.from(this.resolver['_factories'].values()); 
const factory = factories.find((x: any) => x.selector === selector); 

Plunker Example

+0

Dzięki ale takie podejście wydaje mi się krucha. Jeśli rejestr elementów składowych nie zostanie publicznie ujawniony przez Angular, wolałbym używać nazwy klasy niż selektora. Pytanie staje się bardziej pytaniem maszynowym niż pytaniem kątowym; to jest, jak utworzyć instancję typu 'MyComponent' przy użyciu łańcucha" MyComponent " – parliament

+0

wow, która była szybką aktualizacją zanim nawet skomentowałem lol. Czy możesz zaktualizować nową wersję pnkr, myślę, że link jest taki sam dla obu. Prawdopodobnie będziesz musiał go rozwidlić – parliament

+0

Dodałem kod – yurzui

1

Możliwe jest również, aby iterację importu:

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

Aktualizacja: lub po prostu :-)

let inputComponent = possibleComponents[componentStringName] 

następnie można utworzyć instancję składnika na przykład:

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

wiadomości, że składnik ma być w @NgModule entryComponents

+0

Dobra odpowiedź dzięki – parliament

Powiązane problemy