ForRoot() & InjectionToken() in action — Angular

Shashank Vivek
4 min readDec 23, 2019

--

In Angular there are some of the concepts which are often overlooked. forRoot() and InjectionToken() are among such topics which are ignored unless we bang our heads on the wall and end up realizing that these are the only options to achieve desired result.

Let’s start by defining a problem and then figuring out the way, we can use forRoot() and InjectionToken() to solve it.

Problem: We want to create a shared module which will contain a config to set boolean values (as flags) to enable or disable some of the features of other modules. Other modules can either be loaded during bootstrapping of Angular app or it can a lazy loaded module.

ForRoot()

forRoot() is used when we want to maintain a single instance (singleton)of a service across the application which will also have lazy loaded modules.

To give an example, take a look at this demo code where the counter is behaving differently for eager and lazy loaded module.

The counter is maintained by a CounterService which resides under SharedModule . Since, the lazy loaded modules creates its own instance of service, we lose thesingleton behavior of the Angular Services.

To fix this, we need to introduce the concept of forRoot() . The working example can be seen here in this demo . This is the same reason, we use it with RouterModule to help RouterService understand the app behavior with several modules.

RouterModule.forRoot(ROUTES)

To get more info about this concept, you can refer slackernoon’s medium article which has some more code included in it. There are other links such as angular docs and stackoverflow answer to know more about it.

InjectionToken

This is little tricky to understand because as per Angular docs:

Use an InjectionToken whenever the type you are injecting is not reified (does not have a runtime representation) such as when injecting an interface, callable type, array or parameterized type.

What does that mean ? (personally, I never got it unless I came across a real use case) . Lets jump into the implementation of the problem mentioned above.

To solve this problem, we need to keep below points in mind:

  1. To share the value of boolean across all modules (eager & lazy) , we need to use forRoot() .
  2. Since we need to set the boolean value to show & hide the components, it would be a good practice to set them at the time of bootstrapping main angular module (in our case app.module.ts).
  3. We need to “store” all boolean values so that it can be used by all other “modules”. (this is where we will use InjectionToken)

Step by step implementation:

Let’s start by implementing forRoot() for shared module. But, there is one special case that we must consider. We need to make sure that the SharedModule is loaded only once with boolean flag.

To make that happen, we need to add some check so that the SharedModule is loaded only once in AppModule. Lets add below code to it:

It’s a good practice which I have picked from angular docs . If you try to re-import the SharedModule , you’ll end up getting error in Dev tool.

Once we are done with single import of SharedModule, we need to create a way to pass boolean values and then store it somewhere in angular app.

Lets write some code and then we’ll discuss the use of InjectionToken()

We also need to modify the static forRoot() logic in shared.module.ts as below:

With static forRoot(conf?: AppConfig) , we can enable the user to pass certain params at the time of importing SharedModule with AppConfig interface.

To access this boolean into the lazy.component.ts , we need to @Inject()

One important thing to note here is that the lazy.component.ts has @Optional() in its constructor.

It is written in such a way because we don’t want the app to enforce the users to declare SharedModule.forRoot({enableLazyComponentDOM: false}) when they don’t want to see it. In such cases, writingSharedModule.forRoot() would set the flag as false using :

this.showDOM = (config)? config.enableLazyComponentDOM : (!!config)

A final working code is here hosted on stackblitz.

If we revisit the definition of InjectionToken :

Use an InjectionToken whenever the type you are injecting is not reified (does not have a runtime representation) such as when injecting an interface, callable type, array or parameterized type.

In the above example, we can justify the use InjectionToken where we used the interface AppConfig to set the value of boolean flag at runtime. It is not a service and it has been injected into the LazyComponent using @Inject.

I hope this article must have helped to understand the use of these terminologies.

Feel free to clap few time if this article has helped you. 😃 👏 👏

--

--