Real World Examples of 5 Common Observable Operators

Reactive Extensions of JavaScript is a library for reactive programming. It is commonly known for its operators. The RxJS Operators are also known as Observable Operators.

What are Operators?

Operators are pure functions. They take observable as input and return output as observable.


5 Common Observable Operators

  • map– a transformation operator works similar to Array.prototype.map
  • switchMap– cancels the inner observable when outer observable emits a value
  • catchError– catches the error and passes to error handling function
  • debounceTime– discards values if emitted in less than specified time
  • takeUntil– automatically unsubscribes from an observable
  • distinctUntilChanged– emits only distinct values and duplicates ignored

Some real world uses of common observable operators

  • Typeahead searchtakeUnitl with debounceTime operator can be used to achieve typeahead search
  • Handle API errorscatchError can be used to handle error on a specific API call (or use global error handler to catch all the api errors at once)
  • Modify the response before binding on page using map operator (map doesn’t modify the existing observable response, instead it returns a new observable)

Let’s understand each of them with examples.

Typeahead Search

Implementing a typeahead search with angular observable operators becomes really easy. It has switchMap, debounceTime, takeUntil etc operators which are very useful in this scenario.

I will use debounceTime and takeUntil to achieve typeahead search. If you would like to know more about why this then visit a Case Study by Brecht Billiet here: Building a safe autocomplete operator

This example covers following observable operators- switchMap debounceTime, distinctUntilChanged and takeUntil

In this example I will search the keyword in OMDB. It requires an API key to be passed in the url. If you do not have a key, get it from here.

Follow the link to get an OMDB API key.

You will get the OMDB API Key in Mail
You will get the OMDB API Key in Mail

app.service.ts


import { Injectable } from "@angular/core";
import { HttpClient } from '@angular/common/http';
import { Observable } from "rxjs";

@Injectable()
export class AppService {
    constructor(private httpClient: HttpClient) {
    }

    movieSearch(q: string): Observable {
        return this.httpClient.get(`https://www.omdbapi.com/?apikey=&s=${q}`);
    }
}

Replace <your api key> with OMDB API key.

typeahead.component.ts file code


import { Component, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { debounceTime, switchMap, takeUntil, skip, distinctUntilChanged } from 'rxjs/operators';
import { AppService } from '../app.service';

@Component({
  selector: 'app-typeahead',
  templateUrl: './typeahead.component.html',
  styleUrls: ['./typeahead.component.scss']
})
export class TypeaheadComponent implements OnInit {
  term$ = new BehaviorSubject('');
  results$ = this.term$
    .pipe(
      debounceTime(1000),
      distinctUntilChanged(),
      switchMap(term =>
        this.appService.movieSearch(term)
          .pipe(
            takeUntil(
              this.term$.pipe(skip(1))
            )
          )
      )
    )
  constructor(private appService: AppService) { }

  ngOnInit(): void {
  }
}

typeahead.component.html file code


IMDB Movie Typeahead Search..

Term- {{term$|async}}
{{results$|async|json}}

The Network calls look like this

Typeahead Search Network Calls
Typeahead Search Network Calls

Handle API Errors

An application should have a global error handler as well. But sometimes you need to show a custom message for a particular API. In that case this catchError comes as a handy operator.

This example covers following observable operators- catchError

Add the code in service file:


catchErrorExample() {
        return this.httpClient.get('some invalid api link here').pipe(catchError(err => throwError('This is a custom Exception')));
}

I have used an invalid URL show that it can throw an error.

Call the catchErrorExample method from component.



constructor(private appService: AppService) { }

  ngOnInit(): void {
    this.appService.catchErrorExample().subscribe(res => {
      console.log('Response', res);
    }, error => {
      console.log('Error comes here', error);
    });
  }

You will notice the error in Browser Console.

Custom Exception using CatchError
Custom Exception using CatchError

Modify API Response

In many of the scenarios the use of map operator comes in. One of them is modify your api response before binding on page.

This example covers following observable operators- map

Suppose you want to append the country code to every phone number based on the user country. Then this operator will help.

In this example I have used json-server to create an users fake API.

db.json file


{
    "users": [
        {
            "id": 1,
            "userName": "jameer",
            "country": "India",
            "phone": "1234567890",
            "email": "jameer@email.com"
        }
    ]
}

Start json server using below command:

json-server --watch db.json

Put getUser function in app.service.ts file.


 getUser(userId: number): Observable {
     return this.httpClient.get(`http://localhost:3000/users/${userId}`);
 }

app.component.ts file


import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';
import { map } from 'rxjs/operators';

export interface UserModel {
  id: number;
  userName: string;
  email: string;
  country: string;
  phone: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  user: UserModel = {} as UserModel;
  constructor(private appService: AppService) {
  }

  ngOnInit() {
    this.getUsers();
  }

  getUsers() {
    this.appService.getUser(1).pipe(
      map((user: UserModel) => {
        return {
          ...user,
          phone: `+91 ${user.phone}`
        }
      })
    ).subscribe(user => {
      this.user = user;
    })
  }
}

app.component.html file


User Detail

UserName: {{user.userName}}
Email: {{user.email}}
Country: {{user.country}}
Phone: {{user.phone}}

The output is:

Modified Response Output
Modified Response Output

You will notice in the response above that it appends +91 at the beginning of Phone number. But initially it was not there in the db.json file. That is done using map operator.

What people are saying about this article

You can support me by following or saying something about this article on Twitter.

What’s next

This article covers real world uses of some common Angular Observable Operators. I hope it could make a little difference in your understanding about RxJS Operators. That’s all for now.

If you are looking to optimize your Angular Project then I would recommend checking out these articles:

5 Best Ways To Optimize Angular For Scaling (2021)

7 Best Ways To Improve Angular Code (2021)

Leave a Reply

Your email address will not be published. Required fields are marked *