Skip to main content

How to use subjects to multicast observers in RxJS

How To Use Subjects To Multicast Observers In RxJS
RxJS is a framework for reactive programming that makes use of observables, which makes it really easy to write asynchronous code.
According to the official documentation, this project is a kind of reactive extension to JavaScript with “better performance, better modularity, better debuggable call stacks, while staying mostly backwards compatible, with some breaking changes that reduce the API surface.”
It is the official library used by Angular to handle reactivity, converting pull operations for callbacks into observables.

Prerequisites

To be able to follow this article’s demonstration, you should have:
  • Node version 11.0 installed on your machine
  • Node Package Manager version 6.7 (usually ships with Node installation)
  • Angular CLI version 7.0
  • The latest version of Angular (version 7)
Confirm that you are using version 7 using the command below, and update to 7 if you are not.
// run the command in a terminal
ng version
Download this tutorial’s starter project here to follow through the demonstrations. Unzip the project and initialize the Node modules in your terminal with this command:
npm install

What are RxJS subjects?

RxJS subjects are observables that also act as observers and provide a platform for data values to be multicasted to more than one observer. An observable can be defined simply as a function that returns a stream of data values to one observer over time.
A subject is a kind of advanced observable that returns values to more than one observer, which allows it to act as a kind of event emitter.

Why are RxJS subjects important?

First of all, it is an observable, so all the methods available for use with observables automatically work with subjects. The additional fact that you can multicast, which means that more than one observer can be set for a subject, is really awesome.
Observables act purely as producers, but subjects can be both producers and consumers, shifting the reach of observables from unicast to multicast. Subjects should be used in place of observables when your subscriptions have to receive different data values. With multicasting, it matches each subscription to its respective observer.

RxJS subject syntax

Inside an Angular project, the syntax for defining an RxJS subject looks like this:
import { Subject } from "rxjs";
ngOnInit(){
const subject = new Subject();
}

Demo

To illustrate RxJS subjects, let us see a few examples of multicasting. If you started reading this post from the start, you will have the starter project open in your VS Code application. Open your app.component.ts file and copy the code below into it:
import { Component, OnInit } from '@angular/core';
import { Subject } from "rxjs";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  ngOnInit(){
   const subject = new Subject();

   subject.subscribe({
    next: (data) => console.log('First observer prints '+ data)
   });

   subject.next(1);
   subject.next(2);
   }
}
You’ll see that unlike the observable, which requires a kind of helper module passed to create it, the subject just needs a new subject construct, and with that, you can go ahead and use it just as you would any observable. If you run the app in development with the dev command:
ng serve
You will see that it logs data values just as we’d expect, emulating a fully functional observable. This means that both the error and the complete values can be passed to the observer.

Working with more than one observer

Remember that one of subjects’ main features is their ability to have more than one observer set that can make reference to it. You will see that in action with the same logic as we have above. Copy the code block below into the app.component.ts file:
import { Component, OnInit } from '@angular/core';
import { Subject } from "rxjs";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  ngOnInit(){
   const subject = new Subject();
   subject.subscribe({
    next: (data) => console.log('First observer prints '+ data)
   });
   subject.next(1);
   subject.subscribe({
    next: (data) => console.log('Second observer prints '+ data)
   });
   subject.next(2);
   subject.next(3);
   }
}
If you save the file and it recompiles, you will notice that although there are two observers for the subject, the various observers still return data values as expected.
If you notice, the second observer did not receive the very first next value because the subject simultaneously holds and efficiently distributes the values according to scope and definition. This is the beauty of using subjects in RxJS.

Subject variants

There are officially three variants of RxJS subjects. They are:
  • Behavior subject
  • Replay subject
  • Async subject

Behavior subject

The behavior subject is a very special type of subject that temporarily stores the current data value of any observer declared before it. Here is a clear illustration — copy the code below into your app component file:
import { Component, OnInit } from '@angular/core';
import { BehaviorSubject } from "rxjs";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  ngOnInit(){
   const subject = new BehaviorSubject(0);
   subject.subscribe({
    next: (data) => console.log('First observer prints '+ data)
   });
   subject.next(1);
   subject.next(2);
   subject.subscribe({
    next: (data) => console.log('Second observer prints '+ data)
   });
   subject.next(3);
   }
}
Here you see that the behavior subject is imported from RxJS, and the new construct must take in an initial value (which was zero in our case). Also, unlike the prior illustration, you see that the very last data value before the new observer was called (the current value 2) was stored and then reported by the new observer even though it was defined after the reference to it.
Behavior Subject
This is exactly what the behavior subject achieves: storing and then passing on the current data value to the new observer.

Replay subject

After viewing the possibilities that comes with the behavior subject variant, any curious person might ask why they can’t store more than the current value. Well, the good news is that with the replay subject, you can. So the replay subject is basically the behavior subject with the option to choose how many values you want to emit from the last observer. Here is a quick example:
import { Component, OnInit } from '@angular/core';
import { ReplaySubject } from "rxjs";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  ngOnInit(){
   const subject = new ReplaySubject(2);
   subject.subscribe({
    next: (data) => console.log('First observer prints '+ data)
   });
subject.next(1);
   subject.next(2);
   subject.subscribe({
    next: (data) => console.log('Second observer prints '+ data)
   });
subject.next(3);
   }
}
Here it is specified that only one last value be emitted from the last observer, so the output in your browser console should be exactly the same save for the initial log line.
Replay Subject
Additionally, this replay subject can take an optional second argument called window time, recorded in milliseconds. It just allows you to time the return.

Async subject

This is the very last variation. It acts exactly the same as the behavior subject but can only execute after a complete method is called. Remember there are three methods that an observable can call: next, error, and complete. So this particular variation emits the very current value only when it sees the complete method call.
import { Component, OnInit } from '@angular/core';
import { AsyncSubject } from "rxjs";
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  ngOnInit(){
   const subject = new AsyncSubject();
   subject.subscribe({
    next: (data) => console.log('First observer prints '+ data)
   });
subject.next(1);
   subject.next(2);
   subject.subscribe({
    next: (data) => console.log('Second observer prints '+ data)
   });
subject.next(3);
   subject.complete();
   }
}
If you run this in your development server, your browser console will look like this:
Async Subject

Conclusion

This is an introductory overview of subjects in RxJS and how important they are in your workflow. There were also illustrations and even explanations of the three variations that subjects come in. Now you can start to use them in your Angular projects — happy hacking!

Comments

Popular posts from this blog

How to use Ngx-Charts in Angular ?

Charts helps us to visualize large amount of data in an easy to understand and interactive way. This helps businesses to grow more by taking important decisions from the data. For example, e-commerce can have charts or reports for product sales, with various categories like product type, year, etc. In angular, we have various charting libraries to create charts.  Ngx-charts  is one of them. Check out the list of  best angular chart libraries .  In this article, we will see data visualization with ngx-charts and how to use ngx-charts in angular application ? We will see, How to install ngx-charts in angular ? Create a vertical bar chart Create a pie chart, advanced pie chart and pie chart grid Introduction ngx-charts  is an open-source and declarative charting framework for angular2+. It is maintained by  Swimlane . It is using Angular to render and animate the SVG elements with all of its binding and speed goodness and uses d3 for the excellent math functio...

Understand Angular’s forRoot and forChild

  forRoot   /   forChild   is a pattern for singleton services that most of us know from routing. Routing is actually the main use case for it and as it is not commonly used outside of it, I wouldn’t be surprised if most Angular developers haven’t given it a second thought. However, as the official Angular documentation puts it: “Understanding how  forRoot()  works to make sure a service is a singleton will inform your development at a deeper level.” So let’s go. Providers & Injectors Angular comes with a dependency injection (DI) mechanism. When a component depends on a service, you don’t manually create an instance of the service. You  inject  the service and the dependency injection system takes care of providing an instance. import { Component, OnInit } from '@angular/core'; import { TestService } from 'src/app/services/test.service'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.compon...

How to solve Puppeteer TimeoutError: Navigation timeout of 30000 ms exceeded

During the automation of multiple tasks on my job and personal projects, i decided to move on  Puppeteer  instead of the old school PhantomJS. One of the most usual problems with pages that contain a lot of content, because of the ads, images etc. is the load time, an exception is thrown (specifically the TimeoutError) after a page takes more than 30000ms (30 seconds) to load totally. To solve this problem, you will have 2 options, either to increase this timeout in the configuration or remove it at all. Personally, i prefer to remove the limit as i know that the pages that i work with will end up loading someday. In this article, i'll explain you briefly 2 ways to bypass this limitation. A. Globally on the tab The option that i prefer, as i browse multiple pages in the same tab, is to remove the timeout limit on the tab that i use to browse. For example, to remove the limit you should add: await page . setDefaultNavigationTimeout ( 0 ) ;  COPY SNIPPET The setDefaultNav...