How to use forRoot() and forChild() in Angular

Angular’s modular architecture allows developers to build scalable and maintainable applications. One key aspect of this modularity is the use of forRoot and forChild methods in Angular modules. In this post, we’ll dive deep into these methods, exploring their purpose, differences, and how to use them effectively with a practical example.

Understanding the Basics

1. What is forRoot?

In Angular, forRoot is a static method used to configure a module with essential providers and settings. It is typically called in the root module of the application during the import of a feature module. The primary purpose of forRoot is to configure services that are intended to be singletons throughout the application.

2. What is forChild?

forChild is used to configure feature modules that can be imported by other modules. It allows multiple instances of the module to be created, each with its own configuration. This is especially useful when the configuration can vary depending on the importing module.

Practical Examples

Configurable Logger Module

Let’s consider a practical example where we build a configurable logger module that logs messages to the console. We will use forRoot and forChild to configure the logger with different log levels in different parts of our application.

Logger Module

// logger.module.ts

import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LoggerService, LogLevel } from './logger.service';

@NgModule({
  imports: [CommonModule],
  providers: [LoggerService],
})
export class LoggerModule {
  static forRoot(logLevel: LogLevel): ModuleWithProviders<LoggerModule> {
    return {
      ngModule: LoggerModule,
      providers: [
        { provide: LogLevel, useValue: logLevel },
      ],
    };
  }

  static forChild(logLevel: LogLevel): ModuleWithProviders<LoggerModule> {
    return {
      ngModule: LoggerModule,
      providers: [
        { provide: LogLevel, useValue: logLevel },
      ],
    };
  }
}

Logger Service

// logger.service.ts

import { Injectable, InjectionToken } from '@angular/core';

export const LogLevel = new InjectionToken<string>('logLevel');

@Injectable()
export class LoggerService {
  constructor(private logLevel: string) {}

  log(message: string): void {
    if (this.logLevel === 'DEBUG') {
      console.log(`[DEBUG] ${message}`);
    }
  }
}

App Module

// app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { LoggerModule } from './logger/logger.module';
import { LoggerService } from './logger/logger.service';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    LoggerModule.forRoot('DEBUG'), // Global configuration for the root module
  ],
  providers: [LoggerService],
  bootstrap: [AppComponent],
})
export class AppModule {}

Feature Module

// feature.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FeatureComponent } from './feature.component';
import { LoggerModule } from '../logger/logger.module';
import { LoggerService } from '../logger/logger.service';

@NgModule({
  declarations: [FeatureComponent],
  imports: [
    CommonModule,
    LoggerModule.forChild('INFO'), // Configuration for the feature module
  ],
  providers: [LoggerService],
})
export class FeatureModule {}

Feature Component

// feature.component.ts

import { Component } from '@angular/core';
import { LoggerService } from '../logger/logger.service';

@Component({
  selector: 'app-feature',
  template: `
    <div>
      <h2>Feature Component</h2>
      <button (click)="logMessage()">Log Message</button>
    </div>
  `,
})
export class FeatureComponent {
  constructor(private loggerService: LoggerService) {}

  logMessage(): void {
    this.loggerService.log('This message will be logged because the log level is INFO in the feature module.');
  }
}

App Component

// app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <h1>Angular Logger Example</h1>
      <app-feature></app-feature>
    </div>
  `,
})
export class AppComponent {}

In this example, the root module (AppModule) configures the logger with a log level of ‘DEBUG’, while the feature module (FeatureModule) configures the logger with a log level of ‘INFO’. The FeatureComponent logs a message when a button is clicked, demonstrating how forRoot and forChild can be used to configure modules and their services in a hierarchical manner within an Angular application.

Next Post Previous Post
No Comment
Add Comment
comment url