ngx-bootstrap: fix(modal): modal does not properly work in a lazy loaded module

To have working modal in a lazy-loaded module you have to import modal module with forRoot() in that lazy module which is not correct as BsModalService will get a new instance and will not know anything about other modals of other modules (e.g. nesting won’t properly work). If you skip the forRoot() you will get:

ERROR Error: No component factory found for MyModalInLazyLoadedModule. 
Did you add it to @NgModule.entryComponents?

That’s happening because ComponentLoaderFactory is provided only in root module which does not know anything about lazy-loaded injector and factories.

Proper fix would be to have some kind of overlay service that is provided with every ModalModule import.

Reproduction - https://stackblitz.com/edit/ngx-bootstrap-playground-mtwpzg

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 37
  • Comments: 25 (1 by maintainers)

Commits related to this issue

Most upvoted comments

@psined1 Just import ModalModule.forRoot() in your lazy-loaded module.

Also having the same issue. The workaround pointed by @dzonatan fixes it, but I don’t know what are the implications of using forRoot in a child module.

advances?

Same problem, after almost two years 😭 Check this reproduction, maybe it will help revive this thread.

As a side note, I’ve tried to apply workaround that @thetric proposed - yes, it works but only until you need BsModalRef service injected into your modal to programmatically manipulate/hide dialog. Another propose was to use <ng-template /> - this will produce a lot of duplicates if you need to reuse it somewhere.

Disappointed…

Nov 2018, still broken?

This is not entirely an angular issue. The way how ng works is not compatible to your guys implementation. The lazy load module encapsulation will never allow provide lazy load factories on global FactoryResolver.

The way ng team and obter libs fixed this issue is working w/ two services. One provided in Module Scope, dedicated to resolve component reference. And a second service provided in root scope to handle multiple modal instances.

In short, the local service will resolve the component reference w/ local factory resolver, and then inject a global service to deal w/ multiple instances of resolved components/modals.

Bringing this issue up again.

I believe this is an Angular issue here. But wow, this issue still not closed.

I needed to perform an action every time I opened a modal in a lazy module to be able to do this. I create a shared module and import the modal module and in the constructor add a listener to the event emiter that the BModalService has. In this way I was not forced to be repeating this in all the modules where I wanted to do this.

I hope you can help them this.

I wouldn’t reimport ModalModule.forRoot() as it will create a new BsModalService and then you’ll have multiple of these services which are trying to manage some global UI state. It would work fine if you don’t plan on using the service to call something like bsModalService.hide(1) from another context (which our app does to force close modals upon a navigation event).

I think the easiest solution would be (while still somewhat kludgy), for the lazy loaded module to provide its own ComponentLoaderFactory and extend ModalOptions to allow us to give our own ComponentLoaderFactory as then it would have the correct underlying ComponentFactoryResolver which could resolve lazy entryComponents (at least according to https://github.com/angular/angular/issues/14324).

¿Any updates on this?

I’m getting multiple modalService instances because of the “ModalModule.forRoot()” workaround, and by doing this I can’t use “setDismissReason” and the “onHide” event properly for all the modals.

Thanks for the great library.

Any update on the issue?