Reputation: 442
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
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