Understanding RxJS Observables & Observers: A Comprehensive Guide

Nandeep Barochiya
5 min readMay 23, 2024

--

In this blog post, we will explore RxJS Observables, their power, and their usage in real-time scenarios within AngularJS applications. We will start with the basics and gradually move towards more advanced topics, providing examples along the way.

RxJS

Observables

What are RxJS Observables?

RxJS Observables are a way to handle asynchronous data streams in JavaScript. They allow you to subscribe, react, and combine data streams to build complex applications. Observables are particularly useful when dealing with user events, HTTP requests, and WebSockets.

Why use RxJS Observables?

Observables offer several advantages over traditional Promise-based approaches:

  1. Multicasting: Observables can share a single subscription with multiple subscribers, reducing the overhead of creating multiple subscriptions.
  2. Operators: Observables provide a rich set of operators to manipulate and transform data streams.
  3. Error handling: Observables offer a unified error-handling mechanism, making it easier to manage errors across different data streams.

Getting Started with RxJS Observables

To get started, you need to install RxJS in your AngularJS project. You can do this using npm:

npm install rxjs

Once installed, you can start using Observables in your AngularJS application.

Basic Example: Handling User Events

Let’s start with a simple example of handling user events using Observables. We will create a button and an output element. When the button is clicked, we will display a random string in the output element.

First, we will implement this using vanilla JavaScript:

document.addEventListener("click", () => {
console.log(`Random Value = ${Math.random().toString(36).slice(2)}`);
});

/* Output:
Random Value = uplrrnwussk
Random Value = vw5is70v51d
*/

Now, let’s implement the same functionality using RxJS Observables:

import { fromEvent } from 'rxjs';
import { map } from 'rxjs/operators';

fromEvent(document, "click")
.pipe(map(() => Math.random().toString(36).slice(2)))
.subscribe((value) => (console.log(`Random Value = ${value}`)));

/* Output:
Random Value = dtdsgz5slc
Random Value = eindvkkitr
*/

At first glance, the RxJS code might seem more complex. However, it becomes more powerful when you need to handle more complex scenarios.

Basic Example: Emits values

Here’s a simple example of creating an Observable in Angular:

import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
subscriber.next('Hello, RxJS!');
subscriber.next('This is a simple Observable.');
subscriber.complete();
});

In this example, we create an Observable that emits two values and then completes.

To subscribe to this Observable, we can use the subscribe method:

observable.subscribe({
next: value => console.log(value),
complete: () => console.log('Observable completed.')
});

/* Output
Hello, RxJS!
This is a simple Observable.
Observable completed.
*/

Advanced Example: Handling HTTP Requests

Let’s consider a more advanced example where we need to handle HTTP requests. We will create an Observable that fetches albums from a random user.

import { fromEvent } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { mergeMap, map } from 'rxjs/operators';

fromEvent(document, 'click')
.pipe(
mergeMap(() =>
ajax
.getJSON(`https://jsonplaceholder.typicode.com/posts?_limit=5`)
.pipe(map((data) => data))
)
)
.subscribe(
(posts) => console.log(posts),
(error) => console.error('Error fetching posts:', error)
);

/* Output
[{…}, {…}, {…}, {…}, …]
0: Object
1: Object
2: Object
3: Object
4: Object
*/

This code uses RxJS to make an HTTP GET request to the JSONPlaceholder API to fetch a list of posts. It listens for a click event on the document object and then uses the mergeMap operator to handle the event and make the request. The ajax.getJSON method is used to make the request, and the map operator is used to transform the response data. Finally, the subscribe method is used to handle the response data and log it to the console.

Observer

An observer is an object that receives notifications from an observable. It consists of three methods: next(), error(), and complete(). The next() method is used to receive notifications that contain data, while the error() method is used to receive notifications that indicate an error has occurred. The complete() method is used to indicate that no more notifications will be received.

Observers are used in RxJS to handle asynchronous data streams. They allow you to write code that reacts to data as it becomes available, rather than writing code that blocks and waits for data to be returned.

Here’s an example of how to use an observer in AngularJS with RxJS:

import { fromEvent } from 'rxjs';
import { ajax } from 'rxjs/ajax';
import { mergeMap, map } from 'rxjs/operators';

const observer = {
next: (value) => console.log('Received value:', value),
error: (err) => console.error('Error:', err),
complete: () => console.log('Observable completed')
};

fromEvent(document, 'click')
.pipe(
mergeMap(() =>
ajax
.getJSON(`https://jsonplaceholder.typicode.com/posts?_limit=5`)
.pipe(map((data) => data))
)
)
.subscribe(observer);

/* Output
Received value: [{…}, {…}, {…}, {…}, …]
*/

In this example, we’re using the fromEvent() function to create an observable that emits an event every time the user clicks on the document. We're then using the mergeMap() and map() operators to make an HTTP request to a REST API and map the response data to a new observable.

Finally, we’re using the subscribe() method to pass in our observer object. The observer object contains three methods: next(), error(), and complete(). When the observable emits a value, the next() method is called with the emitted value as an argument. If an error occurs, the error() method is called with the error object as an argument. When the observable completes, the complete() method is called with no arguments.

By using an observer in this way, we can write code that reacts to data as it becomes available, rather than writing code that blocks and waits for data to be returned. This allows us to create more responsive and efficient applications in AngularJS with RxJS.

Conclusion

In this blog post, we have explored RxJS Observables and their power in handling asynchronous data streams in AngularJS applications. We started with the basics and gradually moved towards more advanced topics, providing examples along the way.

Observables offer several advantages over traditional Promise-based approaches, including multicasting, operators, and unified error handling. We have seen how Observables can be used to handle user events, fetch data from APIs, and combine data streams to build complex applications.

We have also learned about Observers, which are objects that receive notifications from Observables. Observers consist of three methods: next(), error(), and complete(), and they allow us to write code that reacts to data as it becomes available, rather than writing code that blocks and waits for data to be returned.

By mastering RxJS Observables and Observers, we can build more responsive and efficient AngularJS applications that can handle complex data streams with ease. Whether you are a beginner or an experienced AngularJS developer, Observables and Observers are essential tools that can help you build better applications.

RxJS Observables are not Angular-specific and can be used with plain JavaScript. They are a part of the Reactive Extensions Library for JavaScript (RxJS) and can be used in any JavaScript application, including Angular, React, Vue, or even vanilla JavaScript.

So, go ahead and start using Observables and Observers in your applications today. With practice and experience, you will soon master these powerful tools and be able to build complex applications with ease.

Happy coding!

--

--