Manual Injection of Class
Before we dive deep into Angular providers, let’s see how to create an Angular provider by ourselves. Please take a look at the below screenshot. We have created an interface named IManualService. We have two classes implementing the IManualService interface: ManualService and ManualServiceWithLog.

import { InjectionToken } from '@angular/core';
export const MANUAL_SERVICE_TOKEN = new InjectionToken<IManualService>(
  'MANUAL_SERVICE_TOKEN'
);
interface IManualService {
  name: string;
}
export class ManualService implements IManualService {
  public name = 'Manual Service';
  constructor() {}
}
export class ManualServiceWithLog implements IManualService {
  public name = 'Manual Service with logging feature';
  constructor() {
    console.log('I am manual service class with logging feature');
  }
}


For the dependency injection to work, we need to take care of three steps.
Define a Token: Define a token with a name for the injection. The token name is used by IoC to identify the class that needs to be injected whenever the particular token is requested.
    export const MANUAL_SERVICE_TOKEN = new InjectionToken<IManualService>(
      'MANUAL_SERVICE_TOKEN'
    );


Provide the Injection: The provider is the place where we define which class/value needs to be provided whenever we are requesting for a class/value.

Injecting ManualService class

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import {
  MANUAL_SERVICE_TOKEN,
  ManualService,
  ManualServiceWithLog,
} from './services/manual-service/manual-service';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    {
      provide: MANUAL_SERVICE_TOKEN,
      useClass: ManualService,
    },
  ],
};

Injecting ManualServiceWithLog class
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import {
  MANUAL_SERVICE_TOKEN,
  ManualService,
  ManualServiceWithLog,
} from './services/manual-service/manual-service';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    {
      provide: MANUAL_SERVICE_TOKEN,
      useClass: ManualServiceWithLog,
    },
  ],
};

Inject the Token: Inject the token in our component or elsewhere wherever we are using it.
constructor(
   @Inject(MANUAL_SERVICE_TOKEN) private manualService: ManualService
 )

import { Component, Inject, Injectable } from '@angular/core';
import {
  MANUAL_SERVICE_TOKEN,
  ManualService,
} from '../services/manual-service/manual-service';

@Component({
  selector: 'app-books-cart',
  standalone: true,
  imports: [],
  templateUrl: './books-cart.component.html',
})
export class BooksCartComponent {
  value: string = '';
  constructor(
    @Inject(MANUAL_SERVICE_TOKEN) private manualService: ManualService
  ) {
    this.value = manualService.name;
  }
}


Once we take care of the above steps, we are ready with dependency injection. Since I am using Angular 18, the latest version, I am using app.config.ts to configure the providers. Here in this app.config.ts, for the key MANUAL_SERVICE_TOKEN, I am passing the ManualService class.

You can see the name ‘Manual Service’ populating from the ManualService class being printed in the UI. In the app.routes.ts class, instead of passing the ManualService class, if you pass the ManualServiceWithLog class, you can see that name being printed as ‘Manual Service with Logging Feature’. Along with that, we can even observe that the console is being logged.

UI Output while using ManualService Class


UI Output while using ManualServiceWithLog.


I hope from this example, you have understood how to use Dependency Injection in Angular and the use of useClass in providers.