ForRoot and ForChild singleton pattern in Angular 11

ForRoot and ForChild is a pattern for singleton services and allows us to have control of the provider. Angular creates a factory for all the modules, except for the lazy modules, which when loaded on demand, have their factory. In this post, we will cover the understanding of how to inject configurations with forRoot and forChild in Angular and finally, we going to use Angular forroot vs forchild patterns in a simple application. 

ForRoot creates a module that configures the root routing module and directives for the app. When you call RouterModule.forRoot(routes), Angular creates an instance of the Router class globally.

Let’s create route for two modules (dashboard and home), which will be loaded normally and  create another route for our new LazyModule(profile),  here we will specify the path to the module followed by the module’s class name with a hashtag.

const routes: Routes = [
  { path: "dashboard", component: DashboardComponent },
  { path: "home", component: HomeComponent },
  {
    path: "profile",
    loadChildren: () => import("./features/profile/profile.module").then(m => m.ProfileModule)
  }];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { } 

What is ChildRoot?

ForChild creates a module that configures all the directives and the given routes when you call RouterModule.forChild(routes), Angular check Router instance available in the app and register all of these routes with that instance. but does not include the router service. It uses the router service created at the root level.

const routes: Routes = [
  { path: 'setting', component: SettingComponent }
];
@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class ProfileRoutingModule { } 

When you provide values in eager-loaded modules imported into each other, injectors are going to be merged and you will still have only one instance of the service. This gets more complicated with lazy-loaded modules. Each lazy-loaded module gets its own injector

In the forRoot and forChild example above, the “dashboard” and “home” modules are eager-loaded modules and both module’s injectors are common so the counter service count will be the same.

In the same way, we can use couterService for the lazy-loaded module (profile module) but the lazy-loaded module gets its own injector so that counter service count will be the different from “dashboard” and “home” modules.  if we’d implement something like this.

import { Injectable } from "@angular/core";
import { timer } from "rxjs";
import { shareReplay } from "rxjs/operators";

@Injectable()
export class CounterService {
   public timer=timer(0,1000).pipe(shareReplay())
}
 

After successfully running your application, the output of your application should be like the below screen.

forRoot and forChild

When to use ForRoot and ForChild in Angular?

ForRoot is used when a module is “eager” (loads when the application starts). Angular creates a Router instance for all the modules that is going to be injected into the “root” of the modules. When we want to access our providers from any point in the application.

ForChild is used when a module is “lazy” (loads when the module loaded on demand). it has its own injector. specifically, when we want to deliver a provider that is visible only to the “children” modules of our module.

Related Post

Source code available for download

The source code is available on Stackblitz of  the ForRoot and ForChild singleton pattern in Angular 11.

Demo Application URL : URL or https://stackblitz.com/edit/forroot-and-forchild?file=src/app/app.component.ts

  • Post category:Angular
  • Reading time:4 mins read