Home Angular Tutorials Angular Providers : useClass, useValue, useFactory & useExisting

Angular Providers : useClass, useValue, useFactory & useExisting

by aouidane.med.amine
137,480 views 25 min read

In this tutorial , we are going to see how to use angular providers and how to register classes , functions and values using them.

We are also going to learn how to use the three types of token that are used to locate the angular provider ( Type Token ,String Token & instance of injectionToken )

We are also going to see the four ways used to create the dependency (Class Provider , Value Provider , Factory Provider & Aliased Class Provider ) 

Table of Contents

What is a Provider in Angular ?

A provider in angular is a powerful mechanism to configure and register a service, value, or function that can be injected into other components or services in the application.

Generally , the angular providers is a simple array that contains a list of providers and each one of them is identified by a Dependency Injection Token ( DI Token )

When we create a component or a service , Angular creates a related Injector for each one.

This Injector is responsible for performing the dependency injection in the component or the service. 

This Injector reads the dependency from the constructor and looks for the provider in the registered providers and injects the instance based on the constructions provided by the provider.

In the previous tutorial, we discussed Angular Injector and the concept of dependency injection in more detail.

How to register a Provider in Angular ?

We can register a provider using two ways :

  • Register In the Angular component 

To register a provider in an Angular component, you can use the providers property of the @Component decorator.

Here is an example of how you can do this:

 

				
					import { Component, Injectable } from '@angular/core';
import { MyService } from './my.service';

@Injectable()
export class MyService {
  // service code here
}

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  providers: [MyService]
})
export class MyComponent {
  constructor(private myService: MyService) {
    // service is now available for use in the component
  }
}

				
			

In this example, we have defined a service called MyService and registered it as a provider in the MyComponent component.

It is useful If you want to have only one instance of the service per component, and shared it with all the component’s children.

Now, the MyService service can be injected into the component constructor or its methods.

  • Register In the Angular Module

To register a provider in an Angular module, you can use the providers property of the @NgModule decorator.

Here is an example of how you can do this:

				
					import { NgModule } from '@angular/core';
import { MyService } from './my.service';

@NgModule({
  // You can also register multiple providers in the providers array
  providers: [MyService]
})
export class MyModule {
  // module code here
}

				
			

In this example, we have defined a service called MyService and registered it as a provider in the MyModule module.

It is useful if you want to share only one instance of the service across the entirety of our application.

Now, the MyService service can be injected into any component, directive, pipe, or service that is a part of the MyModule module.

Using Provide and Provider in Angular

Angular providers must have two properties in their metadata: the provide function, which is used to create a provider for a token, and the provider object itself, which tells Angular how to obtain a value for a dependency injection token (DI Token).

it is possible to only specify the token in the provider metadata. it means we are using the default configuration for the provider (useClass )

providers: [MyService] –> is the shorthand of –> providers: [provide:MyService, useClass: MyService] 

angular providers

Provide Property

The provide property is the first in the metadata and holds the DI token that identifies the provider.

The Token is used by the angular Injector to search and locate the provider from the registred providers.

It can be a Type , String or an instance of InjectionToken

Provider Property 

the provider property is the second in the metadata.

It holds the provider difinition object to describe to the Angular Injector how to create the dependency instance.

There are four ways to create the dependency instance, which we will discuss in more detail later in this tutorial (useClass, useValue, useFactory, useExisiting )

What is DI Token ?

In Angular, a DI Token is a type that represents a unique object instance. It is used as a key for a dependency injection (DI) provider.

So, the Injector maintains the collection of token-provider pairs in its Providers array, using the DI Token as a key to locate the corresponding provider and When requested, the Injector uses the DI Token to find the appropriate provider in this collection.

We can find 3 types of DI Token in angular : Type , String or InjectionToken

Type Token

In Angular, a type token is a class or interface that is used to identify a particular service or dependency.

It is used when defining a provider for a dependency injection, and when requesting an instance of the service or dependency through dependency injection.

Here is an example of how you might use a type token in Angular to define a provider for a service:

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

@Injectable()
export class MyService {
  // Service implementation goes here
}


				
			
				
					@NgModule({
  providers: [{ provide: MyService, useClass: MyService }]
})
export class MyModule {}
				
			

Then, to request an instance of the MyService service through dependency injection, you can use the type token like this:

				
					import { MyService } from './my.service';

export class MyComponent {
  constructor(private myService: MyService) { }
}

				
			

Type tokens are a powerful feature of Angular’s dependency injection system, as they allow you to specify the exact type of service or dependency that you want to inject,

While also allowing you to use other types of providers, such as value providers, to provide the actual service or dependency.

String Token

In Angular, a string token is a type of dependency injection (DI) token that is represented by a string value. It is used as a key for a DI provider, which tells Angular how to obtain the value for the corresponding dependency.

Here is an example of how to create and use a string token in Angular :

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

export const MY_TOKEN = 'YOUR_TOKEN_NAME';

@Injectable()
export class MyService {
  constructor(@Inject(MY_TOKEN) private value: string) {
    // ...
  }
}

@NgModule({
  providers: [{ provide: MY_TOKEN, useValue: 'my value' }]
})
export class MyModule {}
				
			

In the example above, we create a string token MY_TOKEN and use it to register a provider with an Angular module.

The provider uses the useValue property to specify the value for the token. We can then inject the value into the MyService class using DI.

It is important to note that string tokens do not support type information, so you cannot specify the type of the value that the token represents.

As a result, it is generally recommended to use the InjectionToken type instead of string tokens, as it is a more powerful and flexible alternative

 

Injection Token

In Angular, an InjectionToken is a type that represents a unique object instance.

An InjectionToken is a generic type, so you can specify the type of the value that the token represents. For example:

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

export const API_BASE_URL = new InjectionToken<string>('ApiBaseUrl');

				
			

In this example, we create an InjectionToken for the string 'ApiBaseUrl'.

You can then use the InjectionToken to create a provider for a value or service, and register it with an Angular module:

				
					import { NgModule } from '@angular/core';
import { API_BASE_URL } from './my-config-file';

@NgModule({
  providers: [{ provide: API_BASE_URL , useValue: 'XperTuto.com/api/' }]
})
export class MyModule {}

				
			

In this example, we use the API_BASE_URL token to register a provider that uses the useValue property to specify the value for the token.

You can then inject the value or service into a component or another service using DI:

				
					import { Component } from '@angular/core';
import { API_BASE_URL } from './my-config-file';

@Component({
  // ...
})
export class MyComponent {
  constructor(@Inject(API_BASE_URL) private apiBaseUrl: string) {
    // ...
  }
}

				
			

In this example, we inject the value of the API_BASE_URL token into the MyComponent class using the @Inject decorator.

InjectionToken is a powerful and flexible type that supports type information and can be used with all types of providers. It is the recommended choice for DI tokens in Angular.

The Types of Angular Provider

In Angular, a provider is a way to configure a service or value that can be injected into an Angular application.

There are several types of providers that can be used in Angular:

useClass provider

The useClass provider is a way to configure a class provider in Angular. It allows you to specify the class that should be used as a provider for a particular service or value.

Here is an example of how to use the useClass provider in Angular:

				
					import { NgModule } from '@angular/core';
import { MyService } from './my.service';
import { MyMockService } from './my.mock.service';

@NgModule({
providers: [{ provide: MyService, useClass: MyMockService }]
})
export class MyModule {}
				
			
				
					import { Component } from '@angular/core';
import { MyService } from './my.service';

@Component({
  selector: 'app-root',
  template: '<h1>{{title}}</h1>',
})
export class AppComponent {
  title: string;

  constructor(private myService: MyService) {
    this.title = this.myService.getTitle();
  }
}

				
			

In this example, we are going to use the mock service unstead of the real service

So , in the providers property in the module  we specifies that the MyService service should be provided using the useClass provider.

When the component is instantiated, Angular will create an instance based on the provider configuration.

In our case, Angular will inject an instance of the MyMockService class into the component’s constructor instead of MyService class

The component can then use the mock service to retrieve the title by calling the getTitle() method of the service.

useValue Provider

The useValue provider is a way to configure a value provider in Angular. It allows you to specify the value that should be injected when a particular token is requested.

Here is an example of how to use the useValue provider in Angular to inject a value into a component:

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

@NgModule({
providers: [{ provide: 'site_title_token', useValue: 'your_site_title' }]
})
export class MyModule {}
				
			
				
					import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<h1>{{title}}</h1>'
})
export class AppComponent {
  title: string;

  constructor(@Inject('site_title_token') title: string) {
    this.title = title;
  }
}

				
			

In this example, the AppComponent is a component that injects a value with the token 'site_title_token'.

The providers property of the component’s decorator specifies that the value 'your_site_title' should be provided when the 'site_title_token' token is requested.

When the component is instantiated, Angular will inject the value 'your_site_title' into the component’s constructor. The component can then use the value to set the title of the application.

useFactory Provider

useFactory is a way to specify a factory function in the providers array of the @Injectable decorator or the providers property of an Angular module or component.

Here is an example of using useFactory with a conditional statement in angular module:

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

@NgModule({
providers: [
{ 
  provide: DataService,
  useFactory: (environment: Environment) => {
    if (environment.production) {
      return new ProductionDataService();
    } else {
      return new DevelopmentDataService();
    }
  },
  deps: [Environment]
}
]
})
export class MyModule {}
				
			
				
					import { Component } from '@angular/core';
import { DataService } from './dataService.service';

@Component({
  selector: 'app-root',
})
export class AppComponent {

  constructor(private dataService: DataService) {
  }
}

				
			

The factory function is called when the dataService dependency is injected in the AppComponent.

In the factory ,the Injector checks the mode of the environment to determine which service to return.

If the environment is in production mode, the factory will return an instance of the production mode service, otherwise it will return an instance of the development mode service.

The deps array specifies the dependencies that the factory function depends on, which will be injected when the factory function is called.

useExisting Providers ( Aliased Class )

In Angular, the useExisting provider option is used to create an alias for a provider. It allows you to create a new provider that is a alias for an existing provider, and the new provider will return the same instance as the existing provider.

Here’s an example of how you can use the useExisting provider option in Angular:

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

@Injectable()
export class MyService {
  // implementation of MyService
}

@Injectable()
export class MyOtherService {
  constructor(public myService: MyService) { }
}

@NgModule({
  providers: [
    { provide: MyOtherService, useExisting: MyService }
  ]
})
export class MyModule { }

				
			

In this example, the MyOtherService provider is an alias for the MyService provider.

When MyOtherService is injected, it will receive the same instance of MyService that is provided in the root injector.

This can be useful when you want to provide multiple providers that all return the same instance, or when you want to override a provider in a child module while still using the original provider in the parent module.

useClass vs useExisting Providers in Angular

In Angular, the useClass and useExisting provider options are used to specify a provider for a dependency injection token.

useClass is used to specify a class that should be used as the provider for a dependency injection token. When the dependency is injected, a new instance of the class will be created and provided.

useExisting is used to specify an existing provider that should be used as the provider for a dependency injection token. When the dependency is injected, the same instance of the provider that was already created will be provided.

Here’s an example that demonstrates the difference between useClass and useExisting:

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

@Injectable()
export class MyService {
  // implementation of MyService
}

@NgModule({
  providers: [
    MyService,
    { provide: 'MyServiceAlias', useExisting: MyService },
    { provide: 'MyServiceClass', useClass: MyService }
  ]
})
export class MyModule { }

				
			

In this example, MyService is provided in the root injector. MyServiceAlias is an alias for MyService, so it will return the same instance as MyService.

MyServiceClass is a new provider that uses the MyService class as its provider, so it will create a new instance of MyService when it is injected.

So, the main difference between useClass and useExisting is that useClass creates a new instance of the class when it is injected, while useExisting returns an existing instance of the provider.

References and Links

You may also like