RxJS – Subjects

Introduction

In previous posts we’ve discussed RxJS and saw few examples to understand how to use those in our angular applications

You can check the earlier posts in following links

Today, we’ll discuss Subject which is very useful and powerful feature of RxJS.

We’ll start simple with few examples mostly around the subject theory and then later we’ll put subject to good use by creating an EventBus and an Observable Service which will allow us to send data and notifications b/w components.

Let’s start with the basics first.

A key purpose of subject is to send out notifications.

A subject is a special type of observable that can multicast a value or event to multiple subscriber, meaning it provides a way to send one or more data values to listeners. Any component or service that subscribes to the subject’s observable will receive notification.

A subject is also an observer. An observer allow us to push new data into observable sequence. Any component or other services can feed new values into the subject, using its next method. The new value then multi-cast to all subscribers.

There are various type of subjects available, we’ll cover the followings

  • Subject
  • BehaviorSubject
  • AsyncSubject
  • ReplaySubject

What are Subjects

A subject is a special type of observable that implements the observer interface. So it is both an observable and observer.

Following are few characteristics of a subject.

  • Observable
  • Observer
  • Produce values
  • Proxy values
  • Have state and maintains a list of observers.
  • Multicast instead of unicast

common uses of Subjects are to create action-streams, eventBuses and to implement pub/sub behaviors.

Setup

I’ll be using an existing angular component from earlier post.

To start, I’ve added few buttons to UI as shown below

which resulted in following UI

Then I’ve added code to the click handler for the examples below.

Subject Example

output

another usage can be that subject subscribes to another observable and proxy values. Lets see an example next.

Subject Example – Proxy Values

Subjects can be used to proxy values from a source observable to its observers.

Following is the updated code which models the diagram above

output

As expected each of the subject’s observers received and logged values originally produced by the source$ observable (Greetings!).

They also still received the values (Hello) by calling next() directly on the subject.

However, one limitation with subjects, late subscribers won’t get any of the previous data.

Specialized Subjects

RxJS includes few other specialized subjects, that allow you to implement multicast observables with very specific behavior. We’ll see examples of the followings

  • BehaviorSubject
  • AsyncSubject
  • ReplaySubject

BehaviorSubject

A special type of subject that buffers its last emitted value and emits that value to late subscribers. Behavior subject requires an initial value which it will emits to its subscribers if source has not yet produced a value; Emits most recent value otherwise.

A BehaviorSubject works like a subject, except for two key features:

  • It requires an initial value.
  • It provides current value to any new subscriptions.

It is used by the PublishBehavior() operator.

actionSubject = new BehaviorSubject<string>("");

As we can see that subscriber received the initial value and also the next value.

In angular apps, Behavior subject’s are useful when we navigate away from our components (e.g. list component) and come back to it later and we still get subscription with last notification.

AsyncSubject

Only emits the last value received. Used by the PublishLast() operator.

ReplaySubject

Stores and emits multiple (configurable) values. Used with PublishReplay() operator.

Building an Event Bus

Lets put subjects to some good use by creating an Event Bus.

  • An event bus is going to allow us to send data between different component.
  • It follows the mediator pattern.
  • It uses RxJS subject

Following is a simple yet flexible implementation of Event-Bus:

EventBus

Injecting EventBus

eventBus can be injected via constructor injection

Lets see how emit() and on() methods are setup, which are basically a wrapper around next() and subscribe() methods from subject:

Sending Notification

Sending component will use emit() method to raise events. emit() is internally using next() on the subject.

Receiving Notifications

Receiving component will use on() method for receiving interested event(s). on() is internally using subscribe() on the subject.

Demo

For demonstration purpose, I used rxjs-demos.component to raise the event and app component to subscribe to that event as shown below

after clicking the button we can see that app-component title is updated with the data received via event-bus. Also check inspect window to see the console.log output.

Pros and Cons (EventBus)

Few pros and cons of using event-bus as follows

Pros

  • Simple to Use – call emit() or on()
  • Loosely couple communication
  • Lightweight

Cons

  • becomes harder to track who is triggering the event?
  • can make maintenance more challenging (due to above)
  • must remember to unsubscribe() (e.g. inside ngOnDestroy)

Creating an Observable Service

This service is going to provide not only the ability to subscribe the data changes but also to know where those data changes actually originated from (which is currently limitation of our EventBus service).

This will be more of a publisher/subscriber or observer pattern.

  • Observable service can send data to observers/subscribers.
  • Follows the observer pattern.
  • Uses RxJS subject and observables.

The difference between observable service and EventBus though

  • Observer service is sending the data.
  • Observer service is also source of the changes to the data.

Now, this is a more coupled solution, but in complex scenarios, this pattern provides more visibility into exactly what’s going on.

Also in the diagram above, it shows a single component, but more components can be added as needed.

Following is an example of this approach.

so observable service (UsersService) is the source of data change to subject. App component is simply subscribing to selectedUser$ exposed observable property. So, this pattern can be used if we want to have more control about who is responsible for data-change, which is in this case, UsersService.

This example is using a button-click event wiring to a method on the component class, the user data is also being passed, then inside the selectUser() method on component, it is delegating the change to userService.selectUser() method. Based on your requirement, you may or may not want to do that.

If you prefer more loosely coupled approach, then you may use the EventBus approach.

Clearing up a subscription

To prevent memory leaks, we should unsubscribe when we are done with subscription. We can do this in onDestroy hook.

First we create a property to hold the subscription. When we subscribe, we store the subscription in this property. Then in ngOnDestroy we unsubscribe to cleanup.

Summary

In this post, we learned that, A key purpose of subject is to send out notifications. A subject is a special type of observable that can multicast a value or event to multiple subscriber. Any component or service that subscribes to the subject’s observable will receive notification.

You can check the source code available form this git repo.

The deployed sample application is available on this URL.

Let me know if you have some comments or questions. Till next time, Happy coding.

1 thought on “RxJS – Subjects”

Comments are closed.