In this tutorial, we will learn Angular providers with example. Angular Providers allows us to register classes, functions or values (dependencies) with the Angular dependency injection system. The Providers are registered using the token. The tokens are used to locate the provider. We can create three types of the token. Type Token, string token & Injection Token. The Provider also tells Angular injector how to create the instance of dependency. There are four ways by which you can create the dependency: They are Class Provider (useClass), Value Provider (useValue ), Factory Provider ( useFactory ), and Aliased Class Provider ( useExisting).
Applies to: Angular 2 to the latest edition of i.e. Angular 8. Angular 9, Angular 10, Angular 11
We learned how to build an Angular Services and in the Angular Dependency injection tutorial, we learned to how to Inject the Service into another Angular Component or Service. If you are new to Dependency Injection, we recommend you to go through those tutorials before continuing here.
Suggested Readings
Suggested Readings
Angular Services
Angular Dependency Injection
Angular injector, injectable & inject
Angular hierarchical dependency Injection
Table of Content
What are Angular Providers
The Angular Provider is an instruction (or recipe) that describes how an object for a certain token is created. The Angular Providers is an array of such instruction (Provider). Each provider is uniquely identified by a token (or DI Token ) in the Providers Array.
We register the services participating in the dependency injections in the Providers
metadata of the @NgModule
or @Component
or in @Directive
. Where you register the dependency defines the scope of the dependency.
The Angular creates an injector for each component/directive it creates. It also creates a root level injector, which has the app level scope. Each injector gets its own copy of the Providers.
The Angular Components or Angular Services declare the dependencies they need in their constructor. The Injector reads the dependencies and looks for the provider in the providers array using the Token. The injector then instantiates the dependency using the instructions provided in the provider. The Injector then injects the instance of the dependency into the Components/Services.
Configuring the Angular Provider
To Provide an instance of the dependency, we need to register it in the Providers
metadata
In our last tutorial on Angular Dependency injection, we registered our ProductService
using the Providers
arrays as shown below in the @NgModule
1 2 3 | providers: [ProductService] |
The above is an actual shorthand notation for the following syntax
1 2 3 | providers :[{ provide: ProductService, useClass: ProductService }] |
The above syntax has two properties.
Best Angular Books
The Top 8 Best Angular Books, which helps you to get started with Angular
Provide
The First property is Provide
holds the Token or DI Token. The token is used by the injector to locate the provider
in the Providers
array. The Token can be either type
, a string
or an instance of InjectionToken
.
Provider
The second property is Provider
. It tells the Angular how to create the instance of the dependency. The Angular can create the instance of the Dependency in four different ways. It can create a dependency from the existing service class (useClass
). It can inject a value, array or object (useValue
). It can use a factory function, which returns the instance of service class or value (useFactory
). It can return the instance from an already existing token (useExisting
).
DI Token
The injector maintains an internal collection of token-provider map in the Providers array. The token acts as a key to that collection & Injector use the Token (key) to locate the provider
.
Types of DI Token
The DI Token can be either type
, a string
or an instance of InjectionToken
.
Type Token
Here the type being injected is used as the token.
For Example, we would like to inject the instance of the ProductService
, we will use the ProducService
as the token as shown below
1 2 3 | providers :[{ provide: ProductService, useClass: ProductService }] |
The ProductService
is then injected to the component by using the following code.
1 2 3 4 5 | class ProductComponent { constructor(private productService : ProductService ) {} } |
String token
Instead of using a type, we can use a string literal to register the dependency. This is useful in scenarios where the dependency is a value or object etc, which is not represented by a class.
Example
1 2 3 | {provide:'PRODUCT_SERVICE', useClass: ProductService }, |
You can then use the Inject the ProductService
using the @Inject
method
1 2 3 4 5 6 | class ProductComponent { constructor(@Inject('PRODUCTSERVICE') private prdService:ProductService ) { } |
Example:
1 2 3 4 | {provide:'USE_FAKE', useValue: true }, {provide:'APIURL', useValue: 'http://SomeEndPoint.com/api' }, |
1 2 3 4 5 | class ProductComponent { constructor(@Inject('APIURL') private apiURL:string ) } |
Injection Token
The Problem with the string tokens is that two developers can use the same string token at a different part of the app. You also do not have any control over the third-party modules, which may use the same token. If the token is reused, the last to register overwrites all previously registered tokens.
String tokens are easier to mistype and that makes it difficult to track & maintain in big applications.
The Angular provides InjectionToken
class so as to ensure that the Unique tokens are created. The Injection Token is created by creating a new instance of the InjectionToken
class.
InjectionToken Example
First, create a separate file and name it as tokens.ts
. Import the InjectionToken
from @angular/core
library. Create an instance of InjectionToken
and assign it to a const API_URL
1 2 3 4 5 | import { InjectionToken } from '@angular/core'; export const API_URL= new InjectionToken<string>(''); |
Open the AppModule
and the Token is used to register the value in providers
metadata
1 2 3 4 5 6 7 | import { API_URL } from './tokens'; providers: [ { provide: API_URL, useValue: 'http://SomeEndPoint.com/api' } ] |
It is then injected using the @Inject
in the constructor of the service/component.
1 2 3 4 5 6 | import { API_URL } from './tokens'; constructor(@Inject(API_URL) private apiURL: string) { } |
The Types of Provider
The Angular Dependency Injection provides several types of providers.
- Class Provider : useClass
- Value Provider: useValue
- Factory Provider: useFactory
- Aliased Class Provider: useExisting
Class Provider: useClass
The Class Provider useClass
is used, when you want to provide an instance of the class.
1 2 3 | providers :[{ provide: ProductService, useClass: ProductService }] |
In the above, example ProductService
is the Token
(or key) and it maps to the ProductService
Class. In this case both the Class name and token name match.
The Angular Provides a shortcut in cases where both token & class name matches as follows
1 2 3 | providers: [ProductService] |
You can provide a mock/Fake class for Testing purpose as shown below.
1 2 3 | providers :[{ provide: ProductService, useClass: fakeProductService }] |
The above example shows us how easy to switch dependencies.
Value Provider: useValue
The Value Provider useValue
is used, when you want to provide a Simple value
This property can be used when you want to provide URL of Service class, Application wide Configuration Option, etc
1 2 3 | providers :[ {provide:'USE_FAKE', useValue: true}] |
1 2 3 4 5 6 7 8 | const APP_CONFIG = { serviceURL: "www.serviceUrl.com\api", IsDevleomentMode: true }; providers: [{ provide: AppConfig, useValue: APP_CONFIG }] |
Use Object.freeze
to freeze the value of the configuration, so that it cannot be changed
1 2 3 4 5 6 7 8 | const APP_CONFIG = Object.freeze({ serviceURL: "www.serviceUrl.com\api", IsDevleomentMode: true }); providers: [{ provide: AppConfig, useValue: APP_CONFIG }] |
Factory Provider: useFactory
The Factory Provider useFactory
is used when you want to return an object based on a certain condition. The factory function can have an optional argument with dependencies if any.
1 2 3 4 5 6 7 8 | providers :[ {provide:'USE_FAKE', useValue: true}, {provide: ProductService, useFactory: (USE_FAKE) => USE_FAKE ? new FakeProductService() : new ProductService(), deps: ['USE_FAKE']} ] |
The above example code uses useValue
provider to define USE_FAKE
constant
We are then using useFactory
to return either FakeProductService
or ProductService
based on the value of USE_FAKE
Since our Factory Provider depends on ‘USE_FAKE'
, we need to specify it on Deps
array.
Aliased Provider: useExisting
The Aliased Provider useExisting
The provider is used, when you want to use the new provider in place of old Provider.
1 2 3 4 5 6 | providers :[ { provide: ProductService, useExisting: NewProductService }, { provide: NewProductService, useClass: NewProductService } ] |
For Example, in the above example, the ProductService
is mapped to the NewProductService
token using useExisting
Provider. This will return the NewProductService
whenever the ProductService
is used.
Provider Scope
Where you provide the dependency, defines the lifetime of the dependency.
The service provided in the @ngModule
of the root module or any eagerly loaded module are available to be injected everywhere in the application.
The services provided in the @Component
, @pipe
or @Directive
are available to be injected in that component and all the child components
The services provided in the @ngModule
of the lazy loaded module are available to be injected in that module and every component, pipe or directive belonging to that Module.
Singleton services
Each Injector creates a singleton object of the dependency registered by the provider.
For Example, consider a service configured in @ngModule
. Component A asks for the service it will get a new instance of the service. Now if Component B Asks for the same service, the injector does not create a new instance of the service, but it will reuse the already created service.
But if we register the service in @ngModule
and also in Component A. Component A always gets a new instance of the service. While other components gets the instance of the service registered in @ngModule
.
Suggested Reading
The angular hierarchical dependency injection system
Summary
We learned how to register dependencies using the Angular Providers. You can download the sample code from the Github repository. In the next tutorial, we will learn about the Angular injector.
Awesome with your explanation. Thank you so much
Best explanation so far, better than Angulars own documentation.
Well done.
This is the kind of example that drives me nuts:
For Example, we would like to inject the instance of the ProductService, we will use the ProducService as the token as shown below
Why would you use the exact same string for both the “provide” and “useClass”? It makes the example utterly ambiguous. Yes they CAN be the same, but this is an example.
Great acticle, better than angular doc, thanks guy
BEST Tutorial for ‘Angular Providers’ concept. Hats off to the person who wrote it.
Good article, easily to understand, but I got one doubt. When we are injecting DI token as a string or as an instance of InjectionToken, why we have to use @Inject() in the contructor?
We are doing so because we how injector will know which service need to inject as we are not doing anything in constructor that injector will know this the name where I can Inject.
Really useful
Thanks