Angular Providers Example
September 30, 2021
This page will walk through Angular providers example.
1. The
Injector
injects the objects provided by provider into components and services. Those classes which are decorated with @Injectable()
and configured by providers are available for dependency injection (DI).
2. Angular provides different types of providers such as class provider, alias provider, value provider and factory provider. The
Injector
creates singleton object of a class configured by providers.
3. The providers can be configured at module level as well as component level. If a service class is configured using provider in application module then it will be available for all the components configured in this module. If a service is configured using provider in component then it will be available in current component and its children component up to the bottom component.
4. In our application if we have configured a service using providers in root component then it will be available everywhere in the application components and services for dependency injection. It is better to configure service using provider only in that component that itself and its children up to the bottom component can use the service for dependency injection.
5. Generally we configure a service using providers as given below.
providers: [ AnimalService ]
providers: [ { provide: AnimalService, useClass: AnimalService } ]
Contents
Technologies Used
Find the technologies being used in our example.1. Angular 12.1.0
2. Node.js 12.14.1
3. NPM 7.20.3
Injector Providers
A provider provides concrete and runtime version of a dependency value. TheInjector
injects the objects provided by provider into components and services.
1. Provider is configured using
providers
metadata. The providers
metadata is available in @NgModule()
decorator as well as in @Component()
decorator.
2. When
providers
of @NgModule()
decorator configures a service, decorated with @Injectable()
, in application module then that service will be available for dependency injection in all those components which are configured in declarations
metadata of that @NgModule()
decorator.
3. When
providers
of @Component()
decorator configures a service in a component then that service will be available for dependency injection in current component and its children components up to the bottom component.
4. The
Injector
creates singleton object of the class configured by provider for DI. But If we have configured a service in more than one places using provider then object created by injector will be different. Suppose we have two components and they have their respective children components and suppose both components configure same service class. Now for first component, injector will create a singleton object that will be available for first components and its children components up to the bottom component. For second component, injector will create a different singleton object that will be available for second component and its children components up to the bottom component for DI.
5. The
providers
metadata has two parts i.e. token and provider definition object. Token is configured by provide attribute and provider definition object is configured by useClass
, useExisting
, useValue
and useFactory
.
6. We configure providers as following.
a. Using
useClass
for class provider.
providers: [ { provide: AnimalService, useClass: LionService } ]
useExisting
for alias provider.
providers: [ { provide: DesktopService, useExisting: LaptopService } ]
useValue
for value provider.
providers: [ { provide: HELLO_MESSAGE, useValue: 'Hello World!' } ]
useFactory
for factory provider.
providers: [ { provide: PREFERRED_BOOKS, useFactory: preferredBooksFactory(3), deps: [Book, BookService] } ]
All above configurations contain two parts:
1. Token: First part is token configured by provide attribute.
2. Provider Definition Object: Second part is provider definition object configured by
useClass
, useExisting
, useValue
. In case of useFactory
, it is factory method that returns object, string, array etc for dependency injection.
@Injectable()
The Angular@Injectable()
decorator is a marker used at class level. It tells Injector
that this class is available for creation by Injector
. We use @Injectable()
in our service class so that the service object can be created automatically for dependency injection in any component or any other service class. The @Injectable()
decorator is also responsible to instantiate an Angular component, pipe, directive etc. This becomes possible because @Component
, @Pipe
and @Directive
decorators use @Injectable
decorators. If our service class decorated with @Injectable()
has dependency of other service classes, then we need not to worry for its creation and dependency injection will be performed by Injector
automatically.
If our service class has no dependency of other service classes, then it is not necessary to decorate our service class with
@Injectable()
decorator. Still the object of this class can be created by Injector
for dependency injection. But it is better to use @Injectable()
decorator in this case also because in future our service class may need the dependency of other service classes. At that time Injector
will throw error for our service class if not decorated with @Injectable()
. So it is better to use @Injectable()
decorator always at our service class. A class decorated with @Injectable()
is created as following.
@Injectable() export class AnimalService { }
@Injectable()
is the part of @angular/core
API.
If we use
providedIn: 'root'
in @Injectable()
decorator, then we need not to configure this service in providers.
@Injectable({ providedIn: 'root' }) export class AnimalService { }
InjectionToken
TheInjectionToken
creates a token that can be used in dependency injection (DI) provider. If we want to inject any simple data such as string, array, dates, number etc then for their dependency injection we need to create an instance of InjectionToken
as following.
export const HELLO_MESSAGE = new InjectionToken<string>('Hello!');
providers
.
providers: [ { provide: HELLO_MESSAGE, useValue: 'Hello World!' } ]
HELLO_MESSAGE
using constructor in any component or service, we get its value as Hello World!
. We can inject string, array, dates, number etc with the help of @Inject()
decorator in constructor as following.
constructor(@Inject(HELLO_MESSAGE) private message: string) { }
Class Provider: useClass
TheuseClass
is a class provider that creates and returns new instance of specified class. It is used as following.
providers: [ { provide: AnimalService, useClass: LionService } ]
LionService
is the subclass of AnimalService
. Suppose we have used AnimalService
as DI using constructor in any component or service, by above configuration they will get the object of LionService
as DI.
In case of
useClass
configuration, if provider definition is same class as the class used for token given as below.
providers: [ { provide: AnimalService, useClass: AnimalService } ]
providers: [ AnimalService ]
animal.service.ts
import { Injectable } from '@angular/core'; @Injectable() export class AnimalService { name = 'Animal'; food = 'Food'; getName() { return this.name; } getFood() { return this.food; } }
import { Injectable } from '@angular/core'; import { AnimalService } from './animal.service'; @Injectable() export class CowService extends AnimalService { name = 'Cow'; food = 'Grass'; }
import { Injectable } from '@angular/core'; import { AnimalService } from './animal.service'; @Injectable() export class LionService extends AnimalService { name = 'Lion'; food = 'Meat'; }
import { Component, OnInit } from '@angular/core'; import { AnimalService } from './services/animal.service'; @Component({ selector: 'animal-details', template: ` <h3> {{name}} eats {{food}} </h3> ` }) export class AnimalDetailsComponent implements OnInit { name = ''; food = ''; constructor(private animalService: AnimalService) {} ngOnInit() { this.name = this.animalService.getName(); this.food = this.animalService.getFood(); } }
import { Component } from '@angular/core'; import { AnimalService } from './services/animal.service'; import { CowService } from './services/cow.service'; @Component({ selector: 'cow', providers: [ { provide: AnimalService, useClass: CowService } ], template: ` <animal-details></animal-details> ` }) export class CowComponent { }
import { Component } from '@angular/core'; import { AnimalService } from './services/animal.service'; import { LionService } from './services/lion.service'; @Component({ selector: 'lion', providers: [ { provide: AnimalService, useClass: LionService } ], template: ` <animal-details></animal-details> ` }) export class LionComponent { }
import { Component } from '@angular/core'; import { AnimalService } from './services/animal.service'; @Component({ selector: 'any-animal', providers: [ AnimalService ], template: ` <animal-details></animal-details> ` }) export class AnyAnimalComponent { }
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <any-animal></any-animal> <lion></lion> <cow></cow> ` }) export class AppComponent { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { CowComponent } from './cow.component'; import { LionComponent } from './lion.component'; import { AnyAnimalComponent } from './any-animal.component'; import { AnimalDetailsComponent } from './animal-details.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent, CowComponent, LionComponent, AnyAnimalComponent, AnimalDetailsComponent ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { }

Alias Provider: useExisting
useExisting
is an alias provider that maps one token to another.
providers: [ LaptopService, { provide: DesktopService, useExisting: LaptopService } ]
DesktopService
, now they will use LaptopService
. Find the example.
computer.ts
export interface Computer { getComputerName(): string; }
import { Injectable } from '@angular/core'; import { Computer } from './computer'; @Injectable() export class DesktopService implements Computer { getComputerName() { return 'DESKTOP'; } }
import { Injectable } from '@angular/core'; import { Computer } from './computer'; @Injectable() export class LaptopService implements Computer { getComputerName() { return 'LAPTOP'; } }
import { Component, OnInit } from '@angular/core'; import { DesktopService } from './services/desktop.service'; import { LaptopService } from './services/laptop.service'; @Component({ selector: 'computer', providers: [ LaptopService, { provide: DesktopService, useExisting: LaptopService } ], template: ` <h3> I work on {{computerName}} </h3> ` }) export class ComputerComponent implements OnInit { computerName = ''; constructor(private computerService: DesktopService) { } ngOnInit() { this.computerName = this.computerService.getComputerName(); } }
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <computer></computer> ` }) export class AppComponent { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { ComputerComponent } from './computer.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent, ComputerComponent, ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { }

Value Provider: useValue
TheuseValue
is value provider that returns a fixed value for dependency injection. Injector does not create the object in this case but we create the object and that object is configured with provider using useValue
. It is used as following.
Find the two fixed values.
const JAVA_BOOK = new Book('Learning Java', 'Java'); export const HELLO_MESSAGE = new InjectionToken('Hello!');
providers: [ { provide: Book, useValue: JAVA_BOOK }, { provide: HELLO_MESSAGE, useValue: 'Hello World!' } ]
Book
has been injected in any component or service using constructor then the injector will inject fixed value JAVA_BOOK
there. In the same way wherever HELLO_MESSAGE
are injected, they will get Hello World!
value. Now find the example.
book.ts
export class Book { constructor(public name: string, public category: string){} }
import { Component, OnInit, InjectionToken, Inject } from '@angular/core'; import { Book } from './book'; const JAVA_BOOK = new Book('Learning Java', 'Java'); export const HELLO_MESSAGE = new InjectionToken<string>('Hello!'); @Component({ selector: 'book', providers: [ { provide: Book, useValue: JAVA_BOOK }, { provide: HELLO_MESSAGE, useValue: 'Hello World!' } ], template: ` <p>Book Name: <b>{{book.name}}</b> </p> <p>Category: <b>{{book.category}}</b></p> <p>Message: <b>{{message}}</b> </p> ` }) export class BookComponent implements OnInit { constructor(public book: Book, @Inject(HELLO_MESSAGE) public message: string) { } ngOnInit() { } }
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <book></book> ` }) export class AppComponent { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { BookComponent } from './book.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent, BookComponent, ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { }

Factory Provider: useFactory
TheuseFactory
configures a factory provider that returns object for dependency injection. It is used as following.
providers: [ BookService, { provide: Book, useValue: JAVA_BOOK }, { provide: PREFERRED_BOOKS, useFactory: preferredBooksFactory(3), deps: [Book, BookService] } ]
provide: Configures the token that will be used in dependency injection.
useFactory: Configures a factory method that can return object, string, array etc.
deps: Configures the token that will be used by injector to provide dependency injection required by factory method.
Now find the example.
book.component.ts
import { Component, OnInit, InjectionToken, Inject } from '@angular/core'; import { Book } from './book'; import { BookService } from './book.service'; import { PREFERRED_BOOKS, preferredBooksFactory } from './preferred-books' const JAVA_BOOK = new Book('Thinking in Java', 'Java'); @Component({ selector: 'book', providers: [ BookService, { provide: Book, useValue: JAVA_BOOK }, { provide: PREFERRED_BOOKS, useFactory: preferredBooksFactory(3), deps: [Book, BookService] } ], template: ` <h3>Preferred Books</h3> {{preferredBooks}} ` }) export class BookComponent implements OnInit { constructor(@Inject(PREFERRED_BOOKS) private preferredBooks: string) { } ngOnInit() { } }
export class Book { constructor(public name: string, public category: string){} }
import { Injectable } from '@angular/core'; import { Book } from './book' const BOOKS: Book[] = [ {"name": "Head First Java", "category": "Java"}, {"name": "Hibernate in Action", "category": "Hibernate"}, {"name": "Thinking in Java", "category": "Java"}, {"name": "Beginning Hibernate", "category": "Hibernate"}, {"name": "Effective Java", "category": "Java"}, {"name": "Learning Java", "category": "Java"}, {"name": "Hibernate Recipes", "category": "Hibernate"}, ]; @Injectable() export class BookService { getAllBooks(): Book[] { return BOOKS; } }
import { InjectionToken } from '@angular/core'; import { Book } from './book'; import { BookService } from './book.service'; export const PREFERRED_BOOKS = new InjectionToken<string>('book name'); export function preferredBooksFactory(count: number) { return (myBook: Book, bookService: BookService): string => { return bookService .getAllBooks() .filter( book => book.category === myBook.category) .map(book => book.name) .slice(0, Math.max(0, count)) .join(' | '); }; };
Book
and BookService
arguments in factory method is picked up by injector from deps
configuration given below.
{ provide: PREFERRED_BOOKS, useFactory: preferredBooksFactory(3), deps: [Book, BookService] }
preferredBooksFactory()
as argument is the count of books returned by our factory method.
app.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <book></book> ` }) export class AppComponent { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { BookComponent } from './book.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent, BookComponent, ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { }

Run Application
To run the demo application, find following steps.1. Download source code using download link given below on this page.
2. Use downloaded src in your angular CLI application. To install angular CLI, find the link.
3. Run ng serve using command prompt.
4. Now access the URL http://localhost:4200
References
Dependency injection in actionProvider