As described in angular.io, “A service is typically a class with a narrow, well-defined purpose“. In other words, we can see services as a piece of code that does something very specific.
Following a model-view-controller pattern, we want components to render the UI and nothing else.
The logic and every other task (fetching data, updating variables, logging stuff, etc.) should be placed elsewhere, i.e. in services, because they can be reused throughout our application minimizing duplications.
We will create a simple app to explain how services can make Angular apps leaner and better.
App Structure
The app has three components: AppComponent, OneComponent, TwoComponent. They are all peer components in src/app.
We want a service to log clicks from both OneComponent and TwoComponent. Furthermore, the service should remember the total number of clicks.
Here is how the final app looks like:
Creating Angular Services
We start by creating a class inside a newly created file called logging-service.service.ts inside src/app.
The class will get
- a property to store the total number of clicks: clicksNumber
- a helper function called addClick to add a certain number of clicks and log the result
export class LoggingService {
private clicksNumber: number = 0;
addClick(number: number = 1) {
this.clicksNumber += number;
console.log(`
${number} click added.
${this.clicksNumber} clicks in total
`);
}
}
The service is ready. However, there is one last thing we need to do to make the service available everywhere else in the app. We will use the @Injectable() decorator because of some nice properties. Read this if you are interested in understanding more.
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class LoggingService {
private clicksNumber: number = 0;
addClick(number: number = 1) {
this.clicksNumber += number;
console.log(`
${number} click added.
${this.clicksNumber} clicks in total
`);
}
}
Use Angular Services
Finally, we are going to use Angular Services from the components in our app. To keep the example lean, I omitted the parts related to CSS (e.g. classes and properties) but you can find the code on Github.
HTML template
Within the HTML template, we simply add an event listener to bind a click event.
// one.component.html
<div>
<p>Add 1 click</p>
<button (click)="onClick()">Log</button>
</div>
Class
In OneComponent class we inject the service as a dependency. We need to add something to the constructor of one.component.ts so that Angular knows that this component depends on a Service.
In the constructor of one.component.ts, we declare a parameter called logService of type LoggingService.
// one.component.ts
import { Component, OnInit } from '@angular/core';
import { LoggingService } from '../logging-service.service';
@Component({
selector: 'app-one',
templateUrl: './one.component.html',
styleUrls: ['./one.component.css'],
})
export class OneComponent implements OnInit {
constructor(private logService: LoggingService) {}
ngOnInit(): void {}
onClick() {
this.logService.addClick();
}
}
Note that we need to import LoggingService. Then we can use it in the onClick method where we call logService to execute addClick. After this, you can see the result in your console.
Find the rest of the code and a deeper explanation in the original article and on Github.
Things to remember
- A service is a class with a well-defined purpose
- Services are used to separate the logic from the UI (among other things)
- Use @Injectable() decorator to make the service available in the whole app
- Import the service and declare it in the constructor in every component where you need it