components: MatDialog: When using in dynamically loaded component throws error No provider for MatDialog
Reproduction
When using MatDialog in a dynamically loaded component it doesn’t work and throws error No provider for MatDialog
.
Steps to reproduce:
- Follow the instructions in this post (https://medium.com/angular-in-depth/lazy-load-components-in-angular-596357ab05d8 ) to create a dynamically loaded component
- Add
MatDialogModule
to the imports array ofNGModule
for the dynamically loaded component. ng serve
and check the error in console.
Expected Behavior
It should work without throwing any error.
Actual Behavior
Throws below error:
zone-evergreen.js:659 Unhandled Promise rejection: R3InjectorError(AppBrowserModule)[MatDialog -> MatDialog -> MatDialog]:
NullInjectorError: No provider for MatDialog! ; Zone: <root> ; Task: Promise.then ; Value: NullInjectorError: R3InjectorError(AppBrowserModule)[MatDialog -> MatDialog -> MatDialog]:
NullInjectorError: No provider for MatDialog!
at NullInjector.get (http://localhost:4200/vendor.js:34269:27)
at R3Injector.get (http://localhost:4200/vendor.js:48199:33)
at R3Injector.get (http://localhost:4200/vendor.js:48199:33)
at R3Injector.get (http://localhost:4200/vendor.js:48199:33)
at NgModuleRef$1.get (http://localhost:4200/vendor.js:65751:33)
at Object.get (http://localhost:4200/vendor.js:63486:35)
at getOrCreateInjectable (http://localhost:4200/vendor.js:38115:39)
at Module.ɵɵdirectiveInject (http://localhost:4200/vendor.js:52134:12)
at NodeInjectorFactory.MyDynamicallyLoadedComponent_Factory [as factory]
Environment
- Angular: 10.0.0-next.6 (same behavior in other versions e.g. 9.x)
- CDK/Material: 9.2.3
- Browser(s): Chrome
- Operating System (e.g. Windows, macOS, Ubuntu): Windows
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 3
- Comments: 19 (9 by maintainers)
Hello, any news on this? I am having a similar issue. Thanks.
I’ve created a StackBlitz that shows the issue: https://stackblitz.com/edit/19335-before?file=src/main.ts. Here is an example with fix as per (2): https://stackblitz.com/edit/19335-with-fix?file=src/main.ts
The code responsible for loading the actual module with it’s providers is the following. Disclaimer: Can still be optimized with parallel loading but here it’s sufficient for the example:
Closing as this seems to work as expected. Please let us know if this does not work. An issue with an updated StackBlitz would be great. Thanks!
@naveedahmed1 I think the issue here is that you use the
ComponentFactoryResolver
from the root module and directly create the lazy component. It never goes through the lazy app module though, so theMatDialogModule
with its’s root providers (i.e.MatDialog
service) are not having any effect.The right solution would be to either:
MatDialogModule
to the root module so that the service is available in your whole applicationComponentFactoryResolver
for the lazy module and instantiate the component through that.If you go with (2), you might want to use
Compiler#compileModuleSync
, or directly work withNgModuleFactory
. If the module is compiled with ngtsc, then the actual class is considered a factory in Ivy and you could wrap it in aNgModuleFactory
, create an instance of it and then bootstrap a component with it. We have an internal example here (using Ivy factory shims though):https://github.com/angular/components/blob/f0c7a25e0d58440029b4129188baa77d88ce5fc6/src/components-examples/private/load-example.ts#L14-L17
More general best-practices are probably in the Angular docs or in various great blog posts.