Angular 9/8 Services & Dependency Injection via providedIn, root & any Tutorial

  • Author: Ahmed Bouchefra

In this tutorial, we'll be learning about Angular services using the latest Angular 9 version. We'll also learn about dependency injection and its mechanisms such as the @Injectable decorator and the providedIn property which can take the rootand any values or a specific module that will be explaining next.

The any value of provideIn is introduced in Angular 9.

What is an Angular 9 Service?

An Angular service is simply a TypeScript class that encapsulates the various methods for completing a certain task in your app such as getting and sending data from and to a server.

A service is decorated using the @Injectable() decorator available from the Angular core package which means the service can be injected in the components and the other services.

Injecting an Angular 9 Service

But what does mean when a service is injected?

Angular makes use of Dependency Injection to provide instances of services to various components and services which means we don't need to manually create an instance of the service before using it, we simply tell the dependeny injector that we need to use the service and it will provide the instance. Now, how do we tell the injector that we need a service?

We simply use the constructor of the component/service that needs the instance to define the service(s) that need(s) to be injected.

According to the Angular docs:

Dependency injection (DI), is an important application design pattern. Angular has its own DI framework, which is typically used in the design of Angular applications to increase their efficiency and modularity. Dependencies are services or objects that a class needs to perform its function. DI is a coding pattern in which a class asks for dependencies from external sources rather than creating them itself.

Why do you need to use Angular 9 Services?

Angular services are mostly useful in the following scenarios:

  • for separating the business logic of your app from the rendering logic in components,
  • for sharing the data between multiple components in your Angular app,
  • for easing testing and debugging,
  • for writing re-usable code.

Now that we have learned about Angular services and dependency injection, let's see that by example.

Step 1 - Creating an Angular 9 Service by example using Angular CLI 9

Provided that you have Angular CLI installed on your machine and that you have an Angular 9 project generated:

$ ng new angular-9-service-example

Let's see how to use Angular CLI to generate a service.

Open a new command-line interface, navigate to your project's folder and run the following command:

$ ng generate service data

The command will create the following files in the src/app folder of our project:

  • src/app/data.service.spec.ts
  • src/app/data.service.ts

Open the src/app/data.service.ts file, you should find the following initial code:

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

@Injectable({
  providedIn: 'root'
})

export class DataService {

  constructor() { }  
}

This is a typical TypeScript class decorated with the @Injectable() decorator that tells the Angular dependency injector that the class can be provided and injected as a dependency in the other components or services.

What is providedIn?

The Injectable decorator takes a property called provideIn that have by default the root value.

The providedIn property tells the Angular dependency injection with the "scope" of our service in the application i.e where it can be provided.

Note: Before Angular 6, we used the providers: [] property of the @NgModule decorator.

With Angular 6+ we have the new provideIn property for specifying where the dependencies can be provided. It's officialy named Tree-shakable providers.

Thanks to the providedIn property the service can specify where it can be provided without resorting to use the providers array of the module/component.

Angular 9 services can be provided in the root or in any of the available modules using any or a specific module. The root value is an alias for the AppModule, any is added starting with Angular 9.

Step 2 - Implementing the method(s) of our example Angular 9 service

Now, let's see by example how to implement our Angular service.

For sending HTTP requests, we need to import the HttpClientModule which provides the builtin HttpClient service.

Open the src/app/app.module.ts file and import HttpClientModule then add it the imports array as follows:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    HttpClientModule
   ]
})

Since HttpClient is also a service, we can inject it in our data service via the constructor as follows:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';

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

  apiUrl: string = 'YOUR_API_URL';

  constructor(private httpClient: HttpClient) { }

  fetchData(): Observable<any> {
    return this.httpClient.get(this.apiUrl)
  }
}

Step 3 - Accessing the Angular 9 service methods from components

After defining and implementing the service, you need to inject it into the component(s) where you need to use it.

Let's suppose that we want to use the service in the app component.

Open the src/app/app.component.ts file and import the service as follows:

import { DataService } from './data.service';

Next, you need to inject the service class via the constructor of the component as follows:

export class AppComponent {
  constructor(private dataService: DataService){}
}

Next, we can now call the fetchData() method of our service, for example inside the ngOnInit() lifecycle hook of the component:

import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';

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

export class AppComponent implements OnInit {

  constructor(private dataService: DataService) { }

  ngOnInit() {
    this.dataService.fetchData().subscribe(data =>{
        console.log(data);
    });
  }
}

Since the get() method of HttpClient returns an RxJS observable which gets returned from the fetchData() method, we need to subscribe to it in order to send the actual GET request and receive the response.

Conclusion

In this tutorial, we've seen by example how Angular 9 services work alongside with the other corner concepts like dependency injection, the @Injectable decorator for creating a service from a TypeScrit class and the providedIn property for declaring where the service should be provided in our Angular application which could take the root, any (new in Angular 9) values or a specific Angular module.


Sponsored Links