Angular Providers
Written By: Avinash Malhotra
Updated on
Providers are very import part of Angular Services and Dependency Injection. Providers provides dynamic or runtime values to services. When we inject a service, the injector check the providers to create an instance of service. Providers check on runtime which instance or value should be injected to component, directives, pipes or other services.
Providers are used in component decorator with value as Array. We can also use provide to use useClass, useExisting, useValue or useFactory methods for one or more instances or to use value or function on runtime.
Providers
Lets create a service named Error using Angular CLI. This will gives better understanding of Providers in Service with example.
error.service.ts
Add method printError in class with string parameter msg and print output using console.log() with parameter msg.
<!--app.service.ts-->
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ErrorService {
constructor() { }
printError(msg:string){ console.log( msg ) }
}
Add service providers in component
Add providers in component decorator with service name in array. The token value of array is ErrorService here. Angular will create a instance of ErrorService.
In constructor of AppComponent, use private property with value ErrorService.
Add a method setError and get then value from argument err.
<!--app.component.ts-->
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ErrorService } from './error.service';
@Component({
selector: 'app-root',
standalone: true,
imports:[HomeComponent, FormsModule],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
providers: [ErrorService]
// providers: [provide: ErrorService, useClass: ErrorService]
})
export class AppComponent {
title = 'myApp';
constructor( private errorservice: ErrorService,){ }
err:string="";
setError(){
this.errorservice.printError(this.err);
}
}
app.component.html
In the view layer, add an input with to way data binding. Add a button with click event and call function setError on click.
On the click of button, the input's value will be shown as error in console.
<!--app.component.ts-->
<h1>{{title}}</h1>
<input type="text" [(ngModel)]="err">
<button (click)="setError()">Click</button>
provide
The provide property in providers array of object hold token which serves as key for locating Dependency value or Dependency registration. The token can be string, type or instance of InjectionToken.
The second property is provider definition object used to create dependency value. Four possible values are
S No | Method | Description | Where to use |
---|---|---|---|
1 | useClass | Create new instance of class | Standard dependency injection for services |
3 | useExisting | Provides an existing dependency under a new token | Aliasing services, implementing specific service interfaces |
2 | useValue | Injects a fixed value directly into the dependency | Configuration settings, mock data in unit tests |
4 | useFactory | Creates a dependency instance using a factory function | Dynamic dependency creation based on runtime conditions |
useClass
provide value useClass create a new instance of class when dependency is injected. The class name itself can be used as value of useClass. Also we can use an alternative class as substitute for existing class name in provider
<!--app.component.ts-->
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
//import { userService } from './error.service';
import { ErrorService } from './error.service';
import { devErrorService } from './devError.service';
@Component({
selector: 'app-root',
standalone: true,
imports:[HomeComponent, FormsModule],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
providers: [{ provide : ErrorService, useClass: devErrorService}],
//providers: [ userService, { provide : ErrorService, useClass: devErrorService}],
})
export class AppComponent {
title = 'myApp';
constructor( private errorservice: ErrorService,){ }
err:string="";
setError(){
this.errorservice.printError(this.err);
}
}
useExisting
useExisting value use alias of existing dependency. Instead of creating a new instance, angular will use existing instance registered under different token. Instead of two instances, there will be one instance only.
<!--app.component.ts-->
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ErrorService } from './error.service';
import { devErrorService } from './devError.service';
@Component({
selector: 'app-root',
standalone: true,
imports:[HomeComponent, FormsModule],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
providers: [{ provide : ErrorService, useExisting: devErrorService}]
})
export class AppComponent {
title = 'myApp';
constructor( private errorservice: ErrorService,){ }
err:string="";
setError(){
this.errorservice.printError(this.err);
}
}
useValue
useValue pass object value instead of creating new instance. This is recommended when an existing value is already available as object or function.
<!--app.component.ts-->
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ErrorService } from './error.service';
@Component({
selector: 'app-root',
standalone: true,
imports:[HomeComponent, FormsModule],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
providers: [{ provide : ErrorService, useValue:{ error: function(err){ console.log(`Injected by ${err}`)}}}]
//providers: [{ provide : ErrorService, useValue:{ a:"a", b: "b" }}]
})
export class AppComponent {
title = 'myApp';
constructor( private errorservice: ErrorService){
console.log( errorservice ); // return { a:"a", b: "b" }
}
}
useFactory
useFactory is recommended when the value is dynamic. For example the instance of either errorservice or devErrorService will be used on runtime.
<!--app.component.ts-->
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ErrorService } from './error.service';
import { LoginService } from './login.service';
@Component({
selector: 'app-root',
standalone: true,
imports:[HomeComponent, FormsModule],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
providers: [{ provide : ErrorService, useFactory: ()=>{
let x=true;
if(x){ return new ErrorService() }
else{ return new devErrorService() }
}}],
deps:[LoginService]
})
export class AppComponent {
title = 'myApp';
constructor( private errorservice: ErrorService){ }
}