Back

Services in Angular: Subject vs BehaviorSubject

Services in Angular: Subject vs BehaviorSubject

RxJS is a library used in Angular applications to manage asynchronous data streams. It introduces the concept of Observables and Subjects to handle data flow. This article will discuss two types of Subjects: Subject and BehaviorSubject, what they are, and how they differ.

To get started, we’ll first need to understand the concept of angular services and observables, which is the key to understanding Subject and BehaviorSubject.

The prerequisites for this article are:

  • Node installed
  • Angular CLI
  • Understanding of JavaScript
  • An already set up Angular project. If you don’t have one, create one.

To do this, navigate to the folder where you want your project installed and run this command:

ng new my_first_project

Follow the steps shown in the terminal to complete the installation.

cd to the just installed project; in my own case it is my_first_project:

cd my_first_project

Start up the development server by running this command:

ng -serve

You should have something like this up in your browser:

Anuglar development server

Now, let’s head back to our tutorial proper.

What Are Angular Services?

Angular services are the foundation of a well-structured and modular Angular application. These services act as singletons, serving as a centralized and shareable source for data, logic, and functionality across various components. Angular supports a modular architecture that improves code reusability and maintainability by enclosing individual business logic or data activities within services.

RxJS plays a significant role in Angular services. It provides a unified approach to dealing with asynchronous data and events. Instead of using promises for one-time events and callbacks for multiple values, RxJS Observables can handle various asynchronous operations.

What Are Observables?

Observables are the foundation of RxJS. They are lazy collections of multiple values over time, allowing for subscribing to data streams and responding to emitted values.

Observables are useful for handling events, asynchronous requests, and handling multiple values. They’re ideal for scenarios like HTTP requests, user inputs, and other event-based operations. Below is an example of how they work:

import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next('Hello');
  subscriber.next('World');
  subscriber.complete();
});

observable.subscribe({
  next: x => console.log(`Got value ${x}`),
  error: err => console.error(`Something wrong occurred: ${err}`),
  complete: () => console.log('Done'),
});

In the code above, an observable is created, emitting two values, ‘Hello’ and ‘World,’ and then completes. When one value is emitted, the next callback is triggered, logging the received value with the message “Got value”. After both values are emitted, the observable completes, invoking the complete callback and logging “Done “. If we were to have an error during the observable’s lifecycle, it would be handled by the error callback.

What are Subjects?

According to the documentation, A Subject is a special type of observable that allows values to be multicasted to many observables. In simple terms, they are special containers that can hold values, and when a new value comes into a subject, that value can be shared with numerous observers at once.

Imagine you have a central hub (the Subject) that can send out messages to multiple people (observers) at the same time. When something new happens, everyone connected to the hub gets notified. This makes Subjects handy in certain programming scenarios, especially in the context of reactive programming with libraries like RxJS. Let’s look at an example of a standard subject.

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { Subject } from 'rxjs';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  subject = new Subject();

  constructor() {
    this.subject.subscribe((res) => {
      console.log('first subscriber', res);
    });
  }
}

In the code above, an instance of the RxJS Subject class is created and named subject. Subsequently, a subscriber is set up in the component’s constructor to listen for emissions from this Subject. However, upon checking the console in the browser, no output is observed since there has been no emission on the Subject at this point.

This is because although we have an observable, there is no emission on the observable, so let’s try to emit a value for a subject.

Right after this. Subject.subscribe function, add this:

this.subject.next('emission 1');

Whenever we emit this, it will emit the value to the subscriber who subscribed before this emission. So, in our case, the emission one will be emitted to the particular subscriber, the “first subscriber”. We’ll see that in our console if we check the result in our browser. It displays that subscriber one gets the emission one.

Screenshot 2023-12-03 at 19.10.33

This means that by default, we are not getting the value, and whenever we are emitting, only subscribers who have the subscription before emission receive the values.

Difference Between Observables and Subjects

Subjects are also a type of observer; the main difference is that in observers, we need a separate observer interface to feed an observable source, but subjects implement both the observer and observable interfaces. In other words, subjects can be both consumers and providers, while observables can be only consumers.

BehaviorSubject

BehaviorSubject is a type of Subject in RxJS that extends the basic Subject class. The key feature of a BehaviorSubject is it requires a default value and remembers the last emitted value. When a new subscriber subscribes to a BehaviorSubject, it immediately receives the last emitted value or the initial value if no values have been emitted yet.

A BehaviorSubject object requires a default value. Using the example we used in objects:

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { BehaviorSubject, Subject } from 'rxjs';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  behaviorSubject = new BehaviorSubject('');

  constructor() {
    this.behaviorSubject.subscribe((res) => {
      console.log('First subscriber', res);
    });
  }
}

In the code above, a subscription is established to the behaviorSubject within the component’s constructor. When the behaviorSubject emits a value, the provided callback function logs a message to the console, indicating that the first subscriber received the emitted value.

If we check the result in the browser, we see that the first subscriber is empty because the behaviorSubject will emit the value once you subscribe. This means that once you subscribe, the default value or the previous value will be triggered immediately. So let’s add emission this time. After this.behaviorSubject.subscribe function, add this:

this.behaviorSubject.next('emission 1');

What happens is that it will first emit the default value and then emit the value we just added:

Screenshot 2023-12-03 at 19.43.36

So, how does it behave when we have two subscribers? Let’s see that by adding another subscriber to the code. Update the constructor code to this:

constructor() {
  this.behaviorSubject.subscribe((res) => {
    console.log('first subscriber', res);
  });

  this.behaviorSubject.next('emission 1'); 
     
  this.behaviorSubject.subscribe((res) => {
    console.log('second subscriber', res);
  });
}

If you check the result in the browser, you’ll see that the ‘first subscriber’ got two emissions and the second subscriber got one emission.

Screenshot 2023-12-03 at 19.10.33

We’ll also experience something similar if we add another emission to it. The first subscriber will be emitted three times, while the second emission will be emitted three times. This is because behaviorSubject will emit the values since you are subscribed to it, and it will emit the default values if no emission is happening or added.

Differences between Subject and BehaviorSubject

The main differences between Subject and BehaviorSubject lie in their handling of emitted values and subscriptions.

Subject does not have default values and will not have the previous value, whereas behaviorSubject will hold the previous value. Also, in Subject, once you emit the value, it will give the value to the subscriptions before the emission, whereas behaviorSubject will emit the values to all the subscribers.

Another difference is that BehaviorSubject is about maintaining the latest state, whereas Subject is about current value emission.

Subject is more suited for one-off or event-driven emissions where the latest state is not required. When you need continuous access to the current or most recent value, use BehaviorSubject.

Conclusion

In this article, we looked at Angular services, RxJS, and observables. We also looked at Subject and BehaviorSubject, how they work, and their differences. The type of subjects is not just limited to Subject and behaviorSubject alone as there are other types of subjects: RelaySubject and AsyncSubject.

When dealing with Angular and RxJS, understanding the distinctions between Subject and BehaviorSubject is critical. Knowing how they handle emitted values and subscriptions lets you choose the right type of Subject for your specific use case. Remember always to consider the characteristics and needs of your data flow when choosing between Subject and BehaviorSubject.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay