Angular 5 - instantiate a component from its name

2020-04-04 03:27发布

问题:

I know how to init components using ComponentFactoryResolver.resolveComponentFactory(AComponentType)

but the method expects a Type, while in my code I have the name of the type as a string.

In the Angular API is there a method to resolve by string? If not, how can I convert a string to a Type in TypeScript?

In case that none of the above is possible I will resort to a map but it's not so straightforward as the components I need to instantiate will come from remotely fetched UMD angular component library.

回答1:

You can do the following:

const classesMap = {
  AComponentType: AComponentType,
  BComponentType: BComponentType
}

And then:

CreateDynamicComponent(typeName: string) {
    ...
    const componentFactory = ComponentFactoryResolver.resolveComponentFactory(classesMap[typeName].prototype.constructor)
    ...
}


回答2:

I had the same problem, where i need to use a string to select what component to build. After some digging I created a list of the components that is added to the NgModuleexport and entryComponents lists.

template-components.ts

export const TEMPLATE_COMPONENTS: Type<any>[] = [
    Temp1Component,
    Temp2Component
  ]

in my NgModule class I just add TEMPLATE_COMPONENTS to both exports and entryComponents

In the component with the ComponentFactoryResolver you generate a list of Types, with the same string as a key.

let templateTypes: { [name: string]: Type<{}> } = 
    TEMPLATE_COMPONENTS.reduce((p, c) => { p[c.name] = c; return p }, {})

// templateTypes = {'Temp1Component':Temp1Component,...}

this.componentFactoryResolver.resolveComponentFactory(templateTypes[string]);

This means that you only have to add the components to one place, simplifying adding more components.

Its probably possible to skip the whole TEMPLATE_COMPONENTSin a separate list step and get the list directly from the NgModuleclass, but that will be sometime in the future.