Services & Dependency Injection

In Previous article we have learnt about Angular Forms, In this article we will look into services and dependency Injection in Angular.

What is Angular Services?

Angular Services are the piece of code or logic that are used to perform some specific task, A code that you can use in many components across application. Also you can say that Angular Services are objects that get instantiated only once during the lifetime of an application. Services contain methods that maintain data throughout the application.

The main objective of a service is to organize and share business logic, models or data and functions will multiple component of an application. Services can be implemented though dependency injection.

What are Angular Services features?

  • Angular Services are simply typescript classes with the @Injectable decorator. This decorator tells angular that this class is a service and it will be injected into components that need this service. 
  • Service are used to share code across multiple components. These service are used to hold business logic.
  • In Angular Components are singleton it means only one instance of a service gets created and same instance is used by every building block in application.
  • A service can be registered as a part of module or as a part of component. To register it as a part of component you have to specify it in the providers array.

What is Dependency Injection?

According to the official Angular documentation, Dependency Injection is a design pattern in which a class requests dependencies from external sources rather than creating them. Angular is having its own built-in dependency injection mechanism that creates and provides runtime version of a dependency value using dependency injector.

Syntax for creating service "ng generate service YourServiceName". 

Now lets take an example, I have created a service "user" using command "ng generate service _service/user". This command will generate two files user.service.ts  and user.service.spec.ts (test case). Below are the default code present when we create a service:

import { Injectable } from '@angular/core';
 
 @Injectable({
 providedIn: 'root'
 })
 export class UserService {
 
 constructor() { }
 }

The first thing that is present in a service is Injectable imported from angular core library and second thing is @Injectable annotation. So Injectable is the main ingredient of dependency injection. The class we have created will provide a service. The @Injectable  decorator marks it as a service that can be injected, or we can say @Injectable decorator is the piece of code that registers a service within angular DI system.

The configuration option providedIn: 'root'  specifies where within the application to provide the service. we are saying provide to 'root' which means root of the app. So this service will be available to entire application.

That's it we can use this service in our component without doing anything else we can use our dependency in the application by injecting as a constructor parameter.

 @Component({
    // standard component metadata here
  })
  export class RegistrationComponent implements OnInit {
    constructor(private userService: userService) { }
  }

Another way to register dependencies is to provide them manually through the providers array. A provider is an object that implements one of the Provider interfaces. A Provider object defines how to obtain an injectable dependency associated with DI token. An injector use the provider to create a new instance of a dependency for a class that requires it. Angular register its providers with every injector, for service that angular defines.

We can register dependency in two ways in Angular:

1. At App Level : When we register the dependency at app level then it creates injected dependency singleton. Example shown below :

import {NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { RegistrationComponent } from './Component/registration/registration.component';
import { FormsModule } from '@angular/forms';
import { NgbModalModule, NgbToastModule } from '@ng-bootstrap/ng-bootstrap';
import { UserService } from './_service/user.service';

@NgModule({
  declarations: [
    AppComponent,
    RegistrationComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    NgbModalModule,
    NgbToastModule,
    FormsModule
  ],
  exports: [
    NgbToastModule
  ],
  providers: [UserService],
  bootstrap: [AppComponent]
})
export class AppModule { }

2. At Component Level : You can also register the dependency at the component level. There is new instance of dependency creation.

import { Component, OnInit } from '@angular/core';
import { UserService } from 'src/app/_service/user.service';

@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styleUrls: ['./registration.component.css'],
  //Inject depedency at component Level
  providers: [UserService],
})
export class RegistrationComponent implements OnInit {
  constructor(  ) { }

  ngOnInit(): void { }

}

Note : To create an angular service as singleton, there are two ways by which we can create singleton services shown in above code snippet.
1. using the providedIn: 'root' , this is the preferred way as it makes the service tree shakable.
2. The second option is to add it in the providers array of @NgModule.

Angular DI Resolution Modifiers

By default Angular dependency injection resolution mechanism starts from component, so when a component ask for any dependency it start looking for dependency from current component ElementInjector, if it does not provide the dependency it will look into the parent component ElementInjector It will check in this hierarchy until it find an injector that provide the service or reaches the root . If ElementInjector does not satisfy the request Angular looks for the dependency in ModuleInjector Hierarchy. 

Resolution Modifiers falls in below category⮞

@Self 🢖🢖 Angular will only look for the dependency in the current component or directives.

When you run your application you can see below error as we have used
@self decorator so angular will look only in this component for service provider but we didn't provide any provider for this dependency. To resolve we have to pass providers array in @Component providers :[UserService]

@SkipSelf 🢖🢖 SkipSelf
decorator is used when we don't want angular to look in the current component and angular starts looking for dependency from parent components. 

@Optional 🢖🢖 Optional decorator is used when we want any dependency to be optional, if the dependency is not found then it will return null instead of throwing error in case of @self, we can use @optional with @self.

@Host 🢖🢖 Host searches for the dependency inside component template only. It does not search inside the providers of host elements but it does search in the viewProviders of the host elements.













Comments

Popular posts from this blog

Introduction to Angular

Bootstrap in Angular

Angular Directives