Configure your Angular apps with an injection token

Dependency injection (DI) is a core concept in Angular, allowing us to efficiently manage and share instances of services and values throughout our application. While DI often involves the injection of classes, there are cases where you need to inject non-class dependencies or provide multiple instances of the same type with different configurations. This is where InjectionToken comes into play.

Understanding InjectionToken

InjectionToken is a powerful feature in Angular that allows us to create a unique token that can be used as a key when defining dependencies for injection. It’s particularly useful when:

  1. You need to inject non-class dependencies, such as configuration values, API endpoints, or string constants.
  2. You want to provide multiple instances of the same type with different configurations.

In this blog post, we’ll explore both scenarios with practical examples to illustrate the power and versatility of InjectionToken.

Scenario 1: Providing a Configuration Value

Imagine you’re developing an Angular application, and you need to provide a configuration value that can be accessed throughout your app. Here’s how you can use InjectionToken for this purpose:

Step 1: Define an InjectionToken

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

// Create an InjectionToken for the configuration value
export const APP_CONFIG = new InjectionToken<string>('app.config');

In this step, we’ve defined an InjectionToken named APP_CONFIG that will represent our configuration value.

Step 2: Provide the Configuration Value

Next, let’s provide the actual configuration value in your Angular module:

import { NgModule } from '@angular/core';
import { APP_CONFIG } from './app-config.token';

@NgModule({
  providers: [
    { provide: APP_CONFIG, useValue: 'codeguru' },
  ],
})
export class AppModule {}

In the above code, we use the provide key to associate our APP_CONFIG token with the value 'codeguru'. You can replace this value with the actual configuration you want to use in your application.

Step 3: Inject and Use the Configuration Value

With the configuration value provided, you can now inject and use it in your components or services:

import { Component, Inject } from '@angular/core';
import { APP_CONFIG } from './app-config.token';

@Component({
  selector: 'app-root',
  template: `
    <div>
      Configuration Value: {{ configValue }}
    </div>
  `,
})
export class AppComponent {
  constructor(@Inject(APP_CONFIG) public configValue: string) {}
}

In the AppComponent, we inject the APP_CONFIG token using Angular’s @Inject decorator and access the configuration value as configValue.

Scenario 2: Providing Multiple Instances

Another common use case for InjectionToken is providing multiple instances of the same type with different configurations. Here’s an example:

Suppose you have two different API endpoints for user data, one for production and one for development. You want to inject the appropriate API endpoint based on the environment.

Step 1: Define InjectionTokens

api-endpoints.tokens

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

// Create InjectionTokens for the API endpoints
export const PROD_API_ENDPOINT = new InjectionToken<string>('prod.api.endpoint');
export const DEV_API_ENDPOINT = new InjectionToken<string>('dev.api.endpoint');

In this step, we’ve created two InjectionTokens, PROD_API_ENDPOINT and DEV_API_ENDPOINT, each representing a different API endpoint.

Step 2: Provide the API Endpoints

Now, let’s provide the actual API endpoints in your Angular module, based on your environment:

import { NgModule } from '@angular/core';
import { PROD_API_ENDPOINT, DEV_API_ENDPOINT } from './api-endpoints.tokens';

@NgModule({
  providers: [
    { provide: PROD_API_ENDPOINT, useValue: 'https://api.example.com' },
    { provide: DEV_API_ENDPOINT, useValue: 'https://dev-api.example.com' },
  ],
})
export class AppModule {}

Here, we’ve provided the production and development API endpoints using the corresponding InjectionToken.

Step 3: Inject and Use the API Endpoint

Now, you can inject and use the appropriate API endpoint in your service:

import { Injectable, Inject } from '@angular/core';
import { PROD_API_ENDPOINT, DEV_API_ENDPOINT } from './api-endpoints.tokens';

@Injectable()
export class ApiService {
  constructor( @Inject(PROD_API_ENDPOINT) private prodApiEndpoint: string,
    @Inject(DEV_API_ENDPOINT) private devApiEndpoint: string ) {}

  getApiEndpoint(isDev: boolean): string {
    return isDev ? this.devApiEndpoint : this.prodApiEndpoint;
  }
}

In the ApiService, we inject both PROD_API_ENDPOINT and DEV_API_ENDPOINT and use a logic (not shown here) to determine which one to use based on the environment.

app.componennt.ts

import { Component, Inject, OnDestroy } from '@angular/core';
import { ApiService } from './api.service';

@Component({
  selector: 'my-app',
  template: `
  <div>
  EndPoint Value: {{ endPoint }}
 
</div>
  `,
  providers: [ApiService],
})
export class AppComponent {
  endPoint: string;
  constructor(private apiSvc: ApiService) {
    this.endPoint = this.apiSvc.getApiEndpoint(true);
  }
}

Demo

InjectionToken is a powerful tool in Angular’s dependency injection system. It enables you to inject non-class dependencies and provide multiple instances of the same type with different configurations. By following the examples provided in this blog post, you can harness the flexibility and versatility of InjectionToken in your Angular applications, making your code more maintainable and adaptable to various scenarios.

Next Post Previous Post
No Comment
Add Comment
comment url