Application Layout

This demo includes three sibling components: AppComponent, OneComponent, and TwoComponent, all located directly under src/app.

The goal is to have a single service that records click events fired from both OneComponent and TwoComponent. In addition, the service must keep track of the cumulative click count.

Below is what the finished interface looks like:
Log Service Angular App

See the app structure

Setting Up an Angular Service

First, a new file named logging-service.service.ts is created inside src/app, containing a plain class.

This class will have:

  1. a field named clicksNumber to hold the running total of clicks
  2. a method called addClick that increments the counter and prints it to the console
export class LoggingService {
  private clicksNumber: number = 0;

  addClick(number: number = 1) {
    this.clicksNumber += number;
    console.log(`
      ${number} click added. 
      ${this.clicksNumber} clicks in total
    `);
  }
}
Enter fullscreen mode Exit fullscreen mode

The service itself is complete. However, for it to be injectable throughout the application, it must be decorated with @Injectable(). This decorator offers certain conveniences that are worth understanding — this article explains the details.

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
    `);
  }
}
Enter fullscreen mode Exit fullscreen mode

Consuming the Service in Components

Now the service needs to be consumed by the app’s components. For clarity, CSS-specific details like classes are omitted here, but the full source is available in the Github repository.

Template

In the markup, a standard click event binding is attached to a button.

// one.component.html

<div>
  <p>Add 1 click</p>
  <button (click)="onClick()">Log</button>
</div>
Enter fullscreen mode Exit fullscreen mode

Component Class

Inside OneComponent, the service is injected through the constructor. Defining a parameter named logService of type LoggingService in the constructor of one.component.ts tells Angular about this dependency.

// 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();
  }
}
Enter fullscreen mode Exit fullscreen mode

The LoggingService must be imported at the top of the file. After that, the onClick handler can invoke logService.addClick(), and the output will appear in the browser console.

For the remaining code and a more thorough walkthrough, refer to the original article and the linked Github repository.

Key Takeaways

  • A service is essentially a class dedicated to a specific purpose
  • Services help keep business logic out of the component layer, among other benefits
  • Applying the @Injectable() decorator makes a service available app-wide
  • For each component that needs the service, import it and add it as a constructor parameter