How to Configure Angular Modules Loaded by the Router
ABP Framework Angular UI has some built-in modules, each of which is a separate npm package. Every package has an exported module that can be loaded by the router. When loaded, these modules introduce several pages to the application via child routes.
To allow a degree of customization, we have an extensibility system, and this requires configuration. So, a question arises: How can we configure modules loaded by loadChildren
? It may look like a requirement specific to our use case, but I believe the method described here may help other subjects.
The Setup
Here is a mere module that attaches a simple component to the path the router loads it.
Let’s load this module with the router.
Do you wish lazy-loading? Well, then we need to do this:
Voila: “foo works!”. Simple, isn’t it? So far, there is nothing impressive but bear with me.
The Twist
Now, let’s make a small change to introduce some configuration options.
You have probably used or created a few modules with the forRoot pattern before. What we did is here similar: We used a static method called withOptions
to make our module configurable. However, we cannot call this method in loadChildren
. Eager or lazy, while loading modules with Angular router, we need to return an NgModuleFactory
, not ModuleWithProviders
. Let’s fix this.
The Factory
Angular core package exports an abstract class called NgModuleFactory
. We will extend it, and implement the abstract methods to convert a ModuleWithProviders
to a module factory for the router.
We pass a ModuleWithProviders
to the ChildModuleFactory
constructor. The following steps happen when the RouterConfigLoader
calls the create
method:
- A new injector is created, using the parent injector and providers from the ModuleWithProviders
in the process.
- Compiler
is retrieved via that injector.
- compileModuleSync
method accesses the moduleType
property, which returns the ngModule
from the ModuleWithProviders
, and creates a factory with it.
- Finally, the module is created using that factory
.
The Solution
Now we will put this factory in use. We are going to add a new static method.
The asChild
static method takes the ModuleWithProviders
returned by the withOptions
method, creates a new instance of ChildModuleFactory
, and returns it. Guess what? We can call this method inside loadChilren
.
What we see on the screen is now “bar works!”. Nice! Besides, you can load the module eagerly and still configure it.
Conclusion
Of course, you can create a wrapper module and pass options through it. Or, maybe you choose to provide tokens directly, and that’s perfectly fine. I have described nothing special, but it’s a clean and reusable way to achieve loading configurable Angular modules.
I have created a StackBlitz playground where you can see the ChildModuleFactory
in action.
Thanks for reading. Have a beautiful day.