Dependency Injection (DI) in Angular
Dependency Injection (DI) is a coding design pattern in which an angular class asks for dependencies from some external sources rather than creating them itself. These dependencies are required by the class before the class gets instantiated.
The definition of DI might seem confusing at first but the example given below will make it more clear.
Create a Component in which we want to inject the service using Dependency injection
ng generate component userslist
Using DI framework we will inject users list to this component from an Injectable service.
Now, create a User service with the command below
ng generate service User
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UserService { constructor() { } }
Note: @Injectable decorator marks a typescript class as a service that you can inject. But before you can inject this service to any component, directive, or pipe in the application, You have to configure this Angular Injector with a provider of that service.
In the above example, we have set the provider as "root" in the Injectable decorator which means this service can be injected into any component anywhere in the application.
You can also limit/restrict the scope of the service in your application.
Create an Interface
ng generate interface user
user.ts
export interface User { firstName: string lastName : string Id : number }
Create a "mock-users.ts" file in the root folder i.e app folder
Right now we have not connected to any server to get users list using the service, so we have created a dummy list in the file to show how a service can be injected into the component.
import { User } from './user'; export const Users: User[] = [ { Id: 1, firstName :" Rahul" , lastName :"Verma" }, { Id: 2, firstName :" Raman" , lastName :"mishra" }, { Id: 3, firstName :" Karan" , lastName :"deora" }, { Id: 4, firstName :" Arjun" , lastName :"Goel" }, ];
Make changes to the User service
This service will be responsible for fetching the users from the mock-user file ( or the database).
import { Users } from './mock-users'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UserService { constructor() { } getUsers() { return Users; } }
The simple task of this service is to return the list of users created in the mock file and that it. As this service is decorated with the @Injectable decorator and has been configured with a provider, It is ready to be injected.
Create a users-list component
ng generate component users-list
import { UserService } from './../user.service'; import { Component, OnInit } from '@angular/core'; import { User } from '../user'; @Component({ selector: 'app-users-list', template : ` <ul> <li *ngFor="let user of userLst"> {{user.Id}} - {{user.firstName}} {{user.lastName}} </li> </ul> ` , styleUrls: ['./users-list.component.css'] }) export class UsersListComponent { userLst: User[] constructor(userService: UserService) { this.userLst = userService.getUsers(); } }
Note that we have injected an instance of the User service into the constructor of the component class.
When we configure an injector with a provider, that provider gets a token which is called DI token. The Injector maintains a token - provider mapper internally. Whenever any component, directive asks for the dependency (service), Injector gets the provider reference from the internal mapper.
You can also Inject one service to the other service
Logging is always a key feature in your application, you can create a log service and inject it to the User service or any other part of the application, depending upon its scope.
Generate a new service using the CLI command:
ng generate service logger
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class LoggerService { logs: string[] = []; // You can save these logs to the database log(message: string) { this.logs.push(message); console.log(message); } }
Now, Open the User service and inject this logger service to the constructor of the User service:
user.service.ts
import { LoggerService } from './logger.service';
import { Users } from './mock-users';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private logger : LoggerService ) {
}
getUsers() {
this.logger.log("Fetching Users...")
return Users;
}
}
To check logs, open the developer tools in the browser and open the console. you should see the logs there.
Create an Optional Dependency in Angular
When angular creates a class whose constructor has parameters, Angular knows that before it executes anything in the component It has a dependency to fetch and inject into the component and if it does not find the dependency information, it throws an error.
Suppose that you want some dependencies to be optional, You can inject a service into the constructor using @Optional() decorator.
import { LoggerService } from './logger.service';
import { Users } from './mock-users';
import { Injectable, Optional } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(@Optional() private logger?: LoggerService ) {
}
getUsers() {
this.logger.log("Fetching Users...")
return Users;
}
}
Now, as you have marked the dependency as optional there are chances that you will get null in the logger. So to handle null values declare the logger property with the "?" as logger?
0 Comments