I need a global modal opener service that can create dynamic components from any module. I have multiple modules and each of them have modal components. I have simplified my project structure like this:
AppModule
---ModalOpenerService
--ModalTemplate
---AModule
---ModalComponent1
---ModalComponent2
---SimpleComponent
---BModule
---ModalComponent3
---ModalComponent4
Modal opener service has a method like this:
@ViewChild('modalContainer', {read: ViewContainerRef}) modalContainer;
showModal(component: Type<any>,data?:any){
let componentFactory = this.resolver.resolveComponentFactory(component);
this.modalContainer.createComponent(componentFactory );
}
I want my ModalOpenerService to be able to create any modal component and show it. But the problem is modal components belong to different modules and modal opener can't find them in its injector's component factory list.
No component factory found for ModalComponent1. Did you add it to @NgModule.entryComponents
Obviously, ModalComponent1 is not a member of AppModule.
I could open modals by passing factory method as a parameter instead of the component type like this:
//In SimpleComponent, I call my ModalOpenerService to open modal1. Because
//the simpleComponent's parent injector (AModule's injector) can find Modal1,
//this.resolver can resolve Modal1.
showModal1(){
this.modalOpenerService.showModal(this.resolver.resolveComponentFactory(ModalComponent1));
}
In ModalOpenerService
@ViewChild('modalContainer', {read: ViewContainerRef}) modalContainer;
showModal(factory:ComponentFactory<any>, data?:any){
this.modalContainer.createComponent(factory);
}
Thus, modules create their own components and they are able to find the component in their entryComponents array.
We have still a problem, because any modal component created in AppModule's scope and if I want to show another modal from a modal, AppModule's injector still won't be able to find it.
One solution can be to put all modals into same module with ModalOpenerService but I want all modals in its own Module.
Any structural design suggestions also welcome
You need to have ModalOpenerService as separate module as be
export class ModelModule {
static WithComponents(components: Array<Type<any>>): Array<any> {
return {
ngModule: ModelModule,
providers: [
{ provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: components, multi: true }
]
}
}
}
And from AModule and BModule you can include a ModelModule as below
@NgModule({
imports: [BrowserModule, ModelModule.WithComponents([ModalComponent1, ModalComponent2])],
declarations: [AppComponent, ModalComponent1, ModalComponent2],
bootstrap: [AppComponent],
providers: []
})
export class AModule { }