Using Angular Signals Service Instead of Observables

With the release of Angular v16 came Signals. An Angular Signal is a variable that can hold a value and also notify its consumers when that value changes, much like an observable work.

In this article, we’ll go through and compare the two approaches when publishing values from an Angular service.

Let’s start with the classic solution, using an Angular service with an observable.

Using Observables to Pass Data

One of the most common solutions for passing data between multiple Angular components which aren’t directly connected is to utilize a service containing an Observable or Subject.

This service will offer a function for accessing a BehaviorSubject as an Observable and another function for pushing new values to it. Let’s create the service:

ng g s observable
import { Injectable } from "@angular/core";
import { BehaviorSubject, Observable } from "rxjs";

@Injectable({
  providedIn: "root",
})
export class ObservableService {
  names$: BehaviorSubject<string> = new BehaviorSubject("Vincent");

  getNames(): Observable<string> {
    return this.names$.asObservable();
  }

  addName(name: string) {
    this.names$.next(name);
  }
}
observable.service.ts

We can now both fetch the latest name and update the name by calling the functions inside the service.

Let’s create a new Angular component where we test out the service:

ng g c names

Let’s inject the service into the component’s constructor and then assign the returned observable to a property inside our component. You can also create the function generateName where a generated name gets published to the service.

export class NamesComponent {
  names: Observable<string>;

  constructor(private observableService: ObservableService) {
    this.names = this.observableService.getNames();
  }

  generateName() {
    this.observableService.addName(faker.person.firstName());
  }
}
names.component.ts

Lastly, we’ll add some HTML and display the latest name published:

<mat-card>
  <h1>Observable</h1>
  <p>{{ names | async }}</p>
</mat-card>
<br />
<button mat-raised-button (click)="generateName()">Generate new name</button>
names.component.html

Here’s the result when we run our application:

Pass Data between multiple Angular components using an Angular service with observables example result

Next up, we’ll take a look at how the same example would look if we use a signal instead of an observable.

Using Angular Signals to Pass Data

You can probably see why the previous approach using an Angular service containing an observable is popular. It is easy to understand and fast to implement but what if there’s a new alternative method that is even easier to implement? There is, let’s dig into Angular Signals.

First, we generate the service which will contain the signal:

ng g s signal

In this service, we’ll have a publicly accessible signal keeping track of the value:

import { Injectable, signal } from "@angular/core";

@Injectable({
  providedIn: "root",
})
export class SignalService {
  public namesSignal = signal("Vincent");
}
signal.service.ts

Next, we can modify the component we created in the previous example so it utilizes the signal service instead of the observable service:

export class NamesComponent {
  constructor(public signalService: SignalService) {}

  generateName() {
    this.signalService.namesSignal.update(() => faker.person.firstName());
  }
}
names.component.ts

Do you see how much cleaner and less code there’s in both the service and the component? That’s the beauty of using signals in Angular!

Our component’s HTML will almost look the same as before except now you can get rid of the async pipe and let the signal handle everything.

<mat-card>
  <h1>Signal</h1>
  <p>{{ signalService.namesSignal() }}</p>
</mat-card>
<br />
<button mat-raised-button (click)="generateName()">Generate new name</button>
names.component.html

And voila! Here’s what it looks like:

Pass Data between multiple Angular components using an Angular service with Angular signals example result

Conclusion

In conclusion, both observables and signals offer several benefits. You can pass data between multiple Angular components using either of these approaches.

The benefit of using signals over observables is that you don’t need to keep track of subscriptions and memory leaks, all that is automatically handled by the Angular Signal system.

Another benefit of using Angular Signals over observables, which many web developers agree on, is that signals are often easier to use and in many cases keep the codebase cleaner than if you would chain RxJs operators on observables.


Maybe you noticed we used Angular Material in our example for styling the application. Are you interested in learning about Angular Material? Then, check out our list of tutorials here.

Leave a Comment