What is an Angular Service?

Service is a piece of reusable code with a focused purpose. A code that you will use across multiple components in your application.

Our components need to access the data. You can write data access code in each Component, but this is very inefficient and breaks the rule of single responsibility. The Component should focus on presenting the data to the user.

The task of receiving data from the back-end server should be delegated to another class. We call a class a service class because it provides each Component with the data it needs.

What is Angular Services used for?

Features independent of components such a logging services

  • Share logic or data across components
  • Encapsulate external interactions like data access
  • Services are easier to test.
  • They are easier to Debug.
  • We can reuse the service at many places.

How to create a Service in Angular

An Angular service is just a JavaScript function. All we have to do is create a class and add methods and properties. Then we can create an instance of this class in our Component and call its methods.

One of the best uses of services is to get data from a data source. Let us create a simple service, which receives product data and sends it to our Component.

Product Model

Please create a new file under the folder src/app and call it product.ts

product.ts

The Product class above is our domain model.

Product Angular Service

Next, we create an Angular service, which returns a list of products.

Please create a new file under the src/app folder and call it product.service.ts.product.service.ts

First, we set the Product model to product.ts. import from

Next, create a ProductService class and export it. We need to export so that components and other service classes import it and use it

The Get Products method returns a collection of products. In this example, we have hardcoded the products. In real life, you would send an HTTP GET request to your back end API to get the data service is ready.

Note that the above class is a simple JavaScript function. There is nothing angular about it.

Invoking the ProductService

The Next step is to invoke the ProductService from the Component. Open the app.componet.ts and add the following code.

app.component.ts

We start with importing Product & ProductService

We create an instance of ProductSerivce in the AppComponent's constructor. In real-life Angular apps, we use dependency injection in Angular to inject ProductSerivce into the constructor. We will learn this in the next tutorial.

The getProducts method calls the getProducts method of the ProductService. It returns a list of products, which we store in local variable products.

What is an Angular Service

Injecting Services into Component

In the example, we instantiated the product-service directly in the Component, as shown below:

As shown above, there are several disadvantages to instantiating the service.

  • Product service is tightly coupled with Components. If we change the definition of the ProductService class, we have to update every code where the service is used.
  • If we want to replace product service with better service, we must search wherever product service is used and replace it manually.
  • Makes testing difficult. We may need to provide counterfeit product service for testing and use product service for production.

We can solve this by using Angular Dependency Injection.

Add Services

Tour of Heroes Heroes component is currently receiving and displaying fake data.

After the refactoring in this tutorial, HeroesComponent will be lean and focused on supporting the view. It will also be easier to unit-test with a mock service.

For the sample application described on this page, see the live example/download example.

Services are a great way to share information between classes that don't know each other. You will create a MessageService and inject it in two places.

  • Inject into HeroService, which uses the service to send messages.
  • Inject into MessagesComponent, which displays the message ID when the user clicks on a hero.

create hero service

Using Angular CLI, create a service called Hero.

The command generates a skeleton HeroService class in src/app/hero.service.ts as follows:

Note that the new service imports the Angular injectable symbol and annotates the class with the @Injectable() decorator. It marks the class that participates in the dependency injection mechanism.

The HeroService class will provide an injectable service and may also have its injectable dependencies. It doesn't have any dependencies yet, but it will soon.

The @Injectable() decorator accepts a metadata object for the service, just as the @Component() decorator did for your component classes.

Get Hero Data

HeroService can get Hero data from anywhere-a web service, local storage, or a simulated data source.

Removing data access from components means that you can change your mind about the implementation at any time without touching any components. They don't know how the service works.

Import the Hero and HEROES.

Provide the HeroService

By registering a provider, you need to make HeroService available to the dependency injection system before Angular can inject it into HeroesComponent. A provider may create or deliver a service; In this case, it instantiates the HeroService class to provide the service.

To ensure that HeroService can provide this service, register it with Injector, the object responsible for selecting and injecting the provider where the application needs it.

By default, the Angular CLI command ng service registers a provider with the root injector for your service by including the provided provider metadata: 'root' in the @Injectable() decorator.

When you provide a service at the root level, Angular creates a single, shared instance of HeroService and injects it into any classes that ask for it. Registering the provider in the @Injectable metadata allows Angular to customize an application by removing the service if it is no longer used.

HeroService is now ready to be plugged into HeroesComponent.

It is an interim code sample that will allow you to provide and use HeroService. The code will be separated from the Hero service in "Final Code Review".

Update Heroes Component

Open the HeroesComponent class file.

Delete the HEROES import because you won't need that anymore. Import the HeroService instead.

Replace the definition of the Hero's property with a declaration.

Inject the HeroService

Add a private heroService parameter of type HeroService to the constructor.

The parameter simultaneously defines a private heroService property and identifies it as a HeroService injection site.

When Angular creates a HeroesComponent, the Dependency Injection system sets the heroService parameter to the singleton instance of HeroService.

Add getHeroes()

Create a method to retrieve the heroes from the service.

Call it in ngOnInit()

While you can call getHeroes() in the constructor, this is not a best practice.

Reserve the constructor for minimal initialization, such as wiring up constructor parameters to properties. The constructor should do nothing. It certainly shouldn't be calling a function that makes an HTTP request to a remote server as an actual data service.

Instead, call getHeroes() inside the ngOnInit lifecycle hook and let Angular call ngOnInit() at the appropriate time after the HeroesComponent instance has been created.

After the browser refreshes, the application should run as before, showing a list of heroes and a hero detail view when you click on a hero name.

Observable data

The HeroService.getHeroes() method has a synchronous signature, implying that the HeroService can fetch heroes synchronously. The HeroesComponent consumes the getHeroes() result as if heroes could be fetched synchronously.

It will not work in a real application. Now you're getting away with it because the service currently returns fake heroes. But soon, the application will fetch heroes from a remote server, which is an inherently asynchronous operation.

HeroService must wait for the server to respond, getHeroes() may not return immediately with hero data, and the browser will not block while the service waits.

HeroService.getHeroes() will return an Observable because it will eventually fetch the Heroes using the Angular HttpClient.get method, and HttpClient.get() returns an Observable.

Observable HeroService

Observable is one of the major classes of the RxJS library.

In a later tutorial on HTTP, you will learn that Angular's HttpClient methods return RxJS Observables. This tutorial will simulate with RxJS of() function to get data from the server.

Open the HeroService file and import the Observables and symbols from RxJS.

content_copyimport { Observable, of } from 'rxjs';

Replace the getHeroes() method with the following:

Of (HEROES) returns an Observablethat emits a single value, the array of mock heroes.

In the HTTP tutorial, you'll call HttpClient.get< Hero []>() which also returns an Observable< Hero []> that emits a single value, an array of heroes from the body of the HTTP response.

Subscribe in HeroesComponent

The HeroService.getHeroes method used to return a Hero[]. Now it returns an Observable .

You'll have to adjust to that difference in HeroesComponent.

Find the getHeroes method and replace it with the below code.

Observable.subscribe() is the critical difference.

The previous version provides an array of heroes for the Component's Heroes property. Assignment occurs when the server may return heroes immediately, or the browser UI may freeze while waiting for the server's response.

The new version waits for the Observable to emit the array of heroes, which can happen several minutes later. The subscribe() method passes the emitted array to the callback, setting the Component's heroes property.

This asynchronous approach will work when HeroService requests heroes from the server.

This section has the following:

  • Message Adding component that displays application messages at the bottom of the screen
  • Creating an injectable, app-wide messaging service for sending messages to display
  • Injecting MessageService into HeroService
  • Displaying a message when HeroService successfully acquires Heroes

create message component

Use the CLI to create the MessagesComponent. The content_copying component generates the message

CLI creates component files in src/app/messages folder and declares MessagesComponent in AppModule.

Modify the AppComponent template to display the generated MessagesComponent.

src/app/app.component.html

You should see the default paragraph from MessagesComponent at the bottom of the page.

Create the MessageService

  • Use the CLI to create the MessageService in src/app.
  • content_copyng generate service message

Open MessageService and replace its contents with the following.

src/app/message.service.ts

The service exposes its cache of messages and two methods: one to add() a message to the cache and another to clear() the cache.

Inject it into the HeroService

In HeroService, import the MessageService.

src/app/hero.service.ts (import MessageService)

Modify the constructor with a parameter that declares a private messageService property. Angular will inject the singleton MessageService into that property when it creates the HeroService.

src/app/hero.service.ts

It typical "service-in-service" scenario: you inject the MessageService into the HeroService, injected into the HeroesComponent.

Send a message from HeroService

Modify the getHeroes() method to send a message when the heroes are fetched.

src/app/hero.service.ts

Display the message from HeroService

The MessagesComponent should display all messages, including the message sent by the HeroService, when it fetches heroes.

Open MessagesComponent and import the MessageService.

Modify the constructor with a parameter that declares a public messaging property. When it creates the MessagesComponent, Angular will inject the singleton MessageService into that property.

src/app/messages/messages.component.ts

The messageService property must be public because you're going to bind to it in the template.

Angular only binds to public component properties.

Bind to the MessageService

Replace the CLI-generated MessagesComponent template with the following.

src/app/messages/messages.component.html

This template connects directly to the Component's messaging.

  • *NGIF displays the message area only if there are messages to be shown.
  • An *ngFor repeatedly presents a list of messages in
    elements.
  • Angular event binding binds the button's click event to MessageService.clear().

Messages will look better when you add private CSS styles to messages.component.css, as listed in one of the "Last Code Review" tabs below.

Add additional messages to the Hero service.

The following example shows how to send and display a message every time the user clicks on a hero, showing the history of the user's selection. It will be helpful when you get to the next part of routing.

More about this source textSource text required for additional translation information

src/app/heroes/heroes.component.ts

Refresh the browser to see the list of Heroes, and scroll down to see HeroService's messages. Each time you click on a hero, a new message appears to record the selection. Use the Clear Message button to clear the message history.

Final code review

Here are the code files discussed on the page.

Summary

You have refactored data access in HeroService class. You have registered HeroService as its service provider at the root level to be inserted anywhere in the application. You used Angular Dependency Injection to inject it into a component. You have given HeroService an asynchronous signature get data method. You discovered Observable and RxJS Observable libraries.

You used RxJS of () to return an Observable of mock heroes (Observable). The Component's ngOnInit lifecycle hook calls the HeroService method, not the constructor. You have created a MessageService for loosely coupled communication between classes.