user2009677
user2009677

Reputation: 442

Angular 7 resolve component factory from selector

I'm developing an Angular 7 lib that has knowledge of a previously declared component (in same or higher module). I have the component selector only at this point, and wish to create that component in container view.

Can that be done? Can I get factory from compiler internals without maintaining a registry of my own?

Thanks

Upvotes: 1

Views: 1894

Answers (1)

Dustin Eastway
Dustin Eastway

Reputation: 11

The below method will work if you can get the Module that declares the component as well as the component's selector.

First, create a helper method to get decorator annotations off of types (I do not believe that this will work with IE or aot compilation):

/**
 * gets a decorator of the requested type off of the given decorated type
 * @param decoratedType to get decorator annotations off of
 * @param decoratorType to search for out of all the decorators on decoratedType
 * @returns decorator from the decoratedType of the decoratorType
 */
export function decoratorOfType<T>(decoratedType: Type<any>, decoratorType: Type<T>): T {
    // get all decorators off of the provided type
    return Reflect.getOwnPropertyDescriptor(decoratedType, '__annotations__').value.find((annotation: any) =>
        // get the decorator that matches the requested type
        annotation instanceof decoratorType
    );
}

This function will make it easy to get the @NgModule decorator of the module that the component is declared in (AppModule in my example):

const ngModuleDecorator = decoratorOfType(AppModule, NgModule);

Using the module decorator you can go through its declarations and find ones with the @Component decorator and a selector set to what you are looking for (app-counter in my example).

const componentType = ngModuleDecorator.declarations.find((declaration: Type<any>) => {
    // get the @Component decorator
    const declarationDecorator = decoratorOfType(declaration, Component);

    // find a declaration with the @Component decorator (not a @Directive) with the requested selector
    return declarationDecorator != null && declarationDecorator.selector === 'app-counter';
});

After you have the component's type you can create the component using a ViewContainerRef and the ComponentFactoryResolver just like other tutorials show you how to dynamically create components:

// get the component factory using the component type
const componentFactory = this._componentFactoryResolver.resolveComponentFactory(componentType as Type<any>);

// fill the content using the component factory
this.dynamicContentDiv.clear();
this.dynamicContentDiv.createComponent(componentFactory);

I have created a working example on StackBlitz that switches between two components depending on what the selected selector is:

Upvotes: 1

Related Questions