Monday, October 30, 2023

Dependency Injection in Angular

 Injecting class dependencies through a constructor[or setter],rather than

 instantiating an object directly is called DI

Dependency Injection is the heart of Angular Applications. The Dependency Injection in Angular is a combination of two terms i.e. Dependency and Injection.

DI will provide singleton behavior to a service class in angular
singleton means creating single object of a service class and used for
 different purposes, this makes single object reusable across different
 components

Dependency: Dependency is an object or service that is going to be used by another object.

Injections: It is a process of passing the dependency object to the dependent object. It creates a new instance of the class along with its require dependencies.


Example

Employee Service

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

@Injectable({
  providedIn: 'root'
})
export class EmployeeService {

  constructor() { }

  getEmployeeDetails(): any[] {
    return [
      {
        ID: 'emp101', FirstName: 'Uday', LastName: 'Kumar',
        Branch: 'CSE', DOB: '29/02/1988', Gender: 'Male'
    },
    {
        ID: 'emp102', FirstName: 'Anurag', LastName: 'Mohanty',
        Branch: 'ETC', DOB: '23/05/1989', Gender: 'Male'
    },
    {
        ID: 'emp103', FirstName: 'Priyanka', LastName: 'Dewangan',
        Branch: 'CSE', DOB: '24/07/1992', Gender: 'Female'
    },
    {
        ID: 'emp104', FirstName: 'Hina', LastName: 'Sharma',
        Branch: 'ETC', DOB: '19/08/1990', Gender: 'Female'
    },
    {
        ID: 'emp105', FirstName: 'Sambit', LastName: 'Satapathy',
        Branch: 'CSE', DOB: '12/94/1991', Gender: 'Male'
    }
    ];
  }
  getTitle():string {
    return "Rajakonda Uday Kumar"
  }
}


.ts Changes


import { Component } from '@angular/core';
import { EmployeeService } from '../employee.service';

@Component({
  selector: 'app-contact',
  templateUrl: './contact.component.html',
  styleUrls: ['./contact.component.css'],
  providers:[EmployeeService]
})
export class ContactComponent {
employee:any[] | undefined
pageTitle: string | undefined;
private _employeeService: EmployeeService | undefined;
constructor(employeeService:EmployeeService) {
  this._employeeService=employeeService;
}
ngOnInit() {
  this.employee=this._employeeService?.getEmployeeDetails();
  this.pageTitle = this._employeeService?.getTitle();
}
}



.html Changes

<h2>{{pageTitle}}</h2>
<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Branch</th>
            <th>DOB</th>
            <th>Gender</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor='let emp of employee'>
            <td>{{emp.ID}}</td>
            <td>{{emp.FirstName}}</td>
            <td>{{emp.LastName}}</td>
            <td>{{emp.Branch}}</td>
            <td>{{emp.DOB}}</td>
            <td>{{emp.Gender}}</td>
        </tr>
    </tbody>
</table>


Output













Understanding Above Code

Here, in the .ts class, we need an instance of Employee Service to call the the getEmployeeDetails() and getTitle() method of Employee Service to get the list of employee data and the title.

 Here we are not creating an instance of Employee Service. Here, we declared a private field _employeeService of type EmployeeService. 

The constructor also has a parameter employeeService of type EmployeeService. Then the constructor initializing the private class field _employeeService with it’s parameter employeeService .

Then we are using this private field _employeeService to call the Employee Service methods getEmployeeDetails() and getTitle().

private _employeeService: EmployeeService | undefined;
constructor(employeeService:EmployeeService) {
  this._employeeService=employeeService;
}


Note:
 Here we are not getting an instance of the EmployeeService class. We are getting instance from constructor.

we can see that the constructor is provided with an instance of EmployeeService class, and then the constructor is assigning that instance to the private field _employeeService.


Who is creating and providing the instance to the constructor?
The answer is Angular Injector. When an instance of .ts class is created, the angular injector creates an instance of the EmployeeService class and provides it to the .ts  constructor. 
The constructor then assigns that instance to the private field _employeeService. We then use this private field _employeeService to call the EmployeeService methods getEmployeeDetails() and getTitle().


How does the angular injector knows about Employee Service?
For the Angular injector to be able to create and provide an instance of Employee Service , first we need to register the Employee Service with the Angular Injector. 
We register a service with the angular injector by using the providers property of @Component decorator or @NgModule decorator. We already know we decorate an angular component with @Component decorator and an angular module with @NgModule decorator.

Service with Angular Injector, this can be done at 3 levels

 1.Component  level
       this will implement DI to a parent component and child components,this
       is called "hierarchical DI", this requires providers option with component decorator
   syntax:
      @Component({
              ...
       providers:[servicename,..]
               })
        ...


Example

Technically,
If you are registering a service using the providers property of the @Component decorator then you are registering the service with an angular injector at the component level. The service is then available to that component and all of it’s children.

Syntax

@Component({
  selector: 'app-contact',
  templateUrl: './contact.component.html',
  styleUrls: ['./contact.component.css'],
  providers:[EmployeeService]
})


2 Module Level

if you register the service using the providers property of the @NgModule decorator then you are registering the service with an angular injector at the module level

Technically

this will implement DI to all the components present with in a
       module, this requires providers option with NgModule decorator
  syntax:
     @NgModule({
             ...
      providers:[servicename,..]
             })
          ...


In appModule.ts
























Example

module1[providers:myservice]
                 |
               object
                 |
  component1     component2           component3       component4
     |                                  |                                 |
constructor        constructor             constructor()
(obj:myservice)  (obj:myservice)    {
 {}                 {}                             obj=new myservice();
                                                         }  

3.application level
          this will implement DI to all the components present with in
          different modules of an application,this requires providedIn
          option with Injectable decorator
    syntax:
         @Injectable({
             providedIn:'root'
                    })


So, in our example, .ts has a dependency on EmployeeService. The .ts receives the dependency instance (i.e employeeService instance) from the the external source (i.e the angular injector) rather than creating the instance itself.


Advantages of Dependency Injection in Angular?
  1. Create applications that are easy to write and maintain over time as the application evolves
  2. Easy to share data and functionality as the angular injector provides a Singleton i.e a single instance of the service
  3. Easy to write and maintain unit tests as the dependencies can be mocked

No comments:

Post a Comment

Thank you for visiting my blog

Kubernetes

Prerequisites We assume anyone who wants to understand Kubernetes should have an understating of how the Docker works, how the Docker images...