How to create an Angular service / Defining and using Angular service inside components

What is a service

A service in Angular is a special typescript class which contains methods and fields like a normal typescript class but its methods and fields can be shared by components. A service is annotated with @Injectable annotation and it is directly injected into the component which wants to use it.

Why is service required

A service is used to perform utility functions such as fetching data from the server, logging to the console, reading a json file etc. Example: Imagine a component wants to fetch data from the server and show it on the browser. Logic to fetch data can be written in the component class itself. But now, some other component also needs to fetch the data from server. You will have to write the same logic in that component too. This way, you will end up duplicating the same code in multiple files. Thus, it is better to write this code outside component, somewhere at a location which can be accessed by multiple components. 

Besides the above, a service is also used to share data between components. Since the same service can be used by multiple components, data written into the service by one component can be read by another component.

Also remember that a service in angular is a singleton object meaning that there is only one instance of service is created and same instance is available to all the components of the module in which the service is registered(more on registration is explained later in the post). This is the reason that a service makes data sharing among components possible. 

How to create a service

Angular cli provides a command to generate services automatically. Open command prompt and navigate to the folder where you want the service class to reside. Now type the following command

ng generate service [service name]

There is also a shortcut to the above command which is

ng g s [service name]

 Where g stands for generate and s stands for service

Example, ng g s codippa

This will generate the following 2 files by default, a service file and unit test file(ending with .spec.ts) for the service. 

Generated service files using angular cli

Notice the file name convention which is the name of service followed by “.service.ts”. This is the naming convention which should be followed by all the services in an angular application.

Also, while generating the service, you only write the name of the service without suffixing it with “service”, that is, for generating service with name CodippaService, you should give only codippa and not codippaservice. If codippaservice is given, then angular cli will create a service with name CodippaServiceService, which is not what you want. 

Structure of a Service

A service class is annotated with @Injectable annotation which means that it can be directly injected into a component. Here is how the above generated service looks like

import { Injectable } from ‘@angular/core’;

@Injectable()

export class CodippaService {

    constructor() { }

    // method to fetch data from server
    public fetchData(): void {
       // logic to fetch data
    }

}

You may or may not want a constructor but service class generated by angular cli contains a constructor. Remove it if you don’t need the constructor but @Injectable annotation is mandatory.

How to use a service

In order to use a service in a component, you need to register a provider of the service and then declare it in the component where it is required.
Registering a provider for the service may be done by any of the following methods

  1. Register the service in the providers array of a module as shown below. This way the service is available to all the components that are part of this module. Since a service is singleton object as outlined earlier, all the components will share the same instance of the service. If the service is registered in the root module of the application, then it will be available to all the components across the application.

    @NgModule({
           providers: [ CodippaService, LoggerService
        })

  2. Register the service in the providers array of component where it is required. Each time the component will be loaded, a new instance of the service will be created. Also, when registered this way, the service will be available only inside the component in which it is registered and its child components.

    @Component({
             selector: ‘codippa‘,
             templateUrl: ‘./codippa.component.html‘,
             providers: [ CodippaService ]    })

  3. Register the provider at the service level itself, inside the @Injectable decorator annotation as shown below. When registered this way, the service is available to all the components across the application and there is only one instance of the service available due to its singleton nature.

    @Injectable({
            providedIn: ‘root
        })

Once the service is registered, you are ready to utilize it in a component. Just declare the service in the constructor of the component and it can be used.

Example, below is a component which utilizes a service,

import Component } from ‘@angular/core’;
import CodippaService } from ‘./codippa.service’;

@Component({
       selector: ‘codippa‘,
       template: ‘./codippa.component.html
})
export class CodippaComponent {

  // inject service
  constructor(codippaService: CodippaService) {
  }

  public showData(): void {
       // use service to fetch data from server
       codippaService.fetchData();
  }

}

Notice how the component declares the service inside its constructor as an argument. When a service is declared inside the constructor and it has been properly registered inside the providers array of the appropriate module of the component itself, then Angular automatically injects an instance of this service into the constructor argument using its Dependency Injection techniques and then it can be easily used inside the component.

If a service is used inside a component but its provider has not been registered anywhere, then you will get a No provider error like

AppComponent.html:1 ERROR Error: StaticInjectorError(AppModule)[CodippaComponent -> CodippaService]:
StaticInjectorError(Platform: core)[CodippaComponent -> CodippaService]:
NullInjectorError: No provider for CodippaService!

Hope this post helped you out in understanding the concept of services in Angular. Do not forget to share it so that others may also benefit from this.

Leave a Reply