The RxJs Subject

Sometimes an Observable lacks what you need to get the job done, one of those needs might be the ability to multicast to many observers, this is one of the benefits of using a Subject.

A Subject is an Observable, you can do anything with a Subject that you can with an Observable, you can, of course, subscribe to it, you can create a pipe of operators, and you can unsubscribe from one.

Now, where Subject differs is that it is also an Observer, that is to say you can call next, error and complete on it as well, this means you can have multiple listeners/observers subscribe to the Subject, and then you can use the next function to pass an event of your choosing to each of their observers.

Interestingly the call to subscribe on a Subject is no different to that of an Observable to the Observer but internally all this does is add that observer to a list of observers that it needs to cast its emits to.

From this brief description, I hope you have many ideas on how you could use a Subject but for now, let's demonstrate the usage of a Subject with an example:

app.component.ts

  1| export class AppComponent{
  2|   public num: number = 0;
  3|   constructor(){
  4|     const subject = new Subject<number>();
  5|      
  6|     subject.pipe(map(val => (val + 100))).subscribe({
  7|       next: (v) => this.num = this.num + v
  8|     });
  9|     subject.subscribe({
10|       next: (v) => this.num = this.num * 2
11|     });
12|      
13|     const source$ = interval(1000);
14|      
15|     source$.subscribe(subject);
16|   }
17| }

app.component.html

  1| {{ num }}

This example has little benefit in any real-world application, but it does demonstrate a few things:

Firstly we can see Subject is an Observer as we are able to pass Subject into our subscribe function from the Observable.

Secondly and much more interestingly we can see that we have made possible the ability to make a unicast Observable able to multicast through the subject.

To understand what I just explained let's look at line 15, we see that we pass subject through to our observable, our Subject now consumes the events from the Observable.

Lines 6 through 8 show us using the Subject as an Observable in that we declare that when we get a value emitted to the subject, we take that value, add one hundred, add the value of the global to the mapped value and then assign to the global.

NOTE: This is to demonstrate the workings of a Subject, not the use case, I don't believe this to be good practice, that is to say, adding values to globals, there are better ways but they fall outside the scope of this topic, read my posts around RxJs operators, eventually I hope to have a post on every one of them and their use cases.

Lines 9 to 11 do the same thing but perform a different operation, you could, of course, change this to merely print the values out, but I find it is useful to see the effects of what we have done here over time.

You will see that both functions are run on any value emitted from the source$ Observable demonstrating the ability of a Subject to allow an Observable the properties of multicasting.

Those that have an Angular background will instantly ask why they should worry about using a Subject when they have EventEmitter.

EventEmitter extends Subject so the thought may be that they are interchangeable and currently, that seems to be the case, in fact, if you change a Subject in the example to be an EventEmitter everything will continue to function.

So we are back to the question of when should we use EventEmitter and when should we favour the Subject?

The answer is very simple; EventEmitter was designed to pass values from child to parent components, that is its use case, essentially if you are not using it for this case then you should almost certainly be using Subject!

The Angular team have been explicit about this intention so don't be surprised if implementations that ignore this intention end up breaking in the future.

There we are, a simple look and introduction to Subjects, they are slighlty more complicated than Observables but offer a lot of valuable benefits, in future posts we will see how some RxJs operators use Subjects under the hood to achieve their functionality as well as look at various 'flavours' of Subjects.


Comments

Popular posts from this blog

Angular material table with angular 7 - Defining columns using ngFor

Creating contextual drop downs using RxJs, Angular 7 and Angular Material

From nothing to an Angular 7 app running in 5 minutes with AWS