Real World Examples of 5 Common Observable Operators
Tags: angular, stackblogger, rxjs, observable
Published: 2021-10-08 14:23:47

The article was originally published to my blog StackBlogger: [Real World Examples of 5 Common Observable Operators](https://stackblogger.com/real-world-examples-of-some-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 search**– `takeUnitl` with `debounceTime` operator can be used to achieve typeahead search
* **Handle API errors**– `catchError` 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](https://blog.strongbrew.io/building-a-safe-autocomplete-operator-with-rxjs/)

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](https://www.omdbapi.com/apikey.aspx?__EVENTTARGET=freeAcct&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE=%2FwEPDwUKLTIwNDY4MTIzNQ9kFgYCAQ9kFgICBw8WAh4HVmlzaWJsZWhkAgIPFgIfAGhkAgMPFgIfAGhkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYDBQtwYXRyZW9uQWNjdAUIZnJlZUFjY3QFCGZyZWVBY2N0oCxKYG7xaZwy2ktIrVmWGdWzxj%2FDhHQaAqqFYTiRTDE%3D&__VIEWSTATEGENERATOR=5E550F58&__EVENTVALIDATION=%2FwEdAAU%2BO86JjTqdg0yhuGR2tBukmSzhXfnlWWVdWIamVouVTzfZJuQDpLVS6HZFWq5fYpioiDjxFjSdCQfbG0SWduXFd8BcWGH1ot0k0SO7CfuulHLL4j%2B3qCcW3ReXhfb4KKsSs3zlQ%2B48KY6Qzm7wzZbR&at=freeAcct&Email=).

![API Key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f72kzd0oolo6d73iqwtq.PNG)

`app.service.ts`
```javascript
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<any> {
        return this.httpClient.get<any>(`https://www.omdbapi.com/?apikey=<your api key>&s=${q}`);
    }
}
```

Replace `<your api key>` with OMDB API key.

`typeahead.component.ts` file code

```javascript
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<string>('');
  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

```html
<div>
    IMDB Movie Typeahead Search..
</div>
<br>
 
<input type="text" (input)="term$.next($any($event.target).value)">
Term- {{term$|async}}
<pre>{{results$|async|json}}
```

**The Network calls look like this**
![Typeahead Search Network Calls](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cb977z00dqzfswjdk980.PNG)

## 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:

```javascript
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.

```javascript
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.**
![Typeahead Search Network Calls](https://stackblogger.com/wp-content/uploads/2021/10/custom-error-min.png)

## 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
```javascript
 
{
    "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

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

`app.component.ts` file

```javascript
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
```html
<div>
  User Detail
</div>
<br>
 
<div>
  <b>UserName: </b> {{user.userName}} <br>
  <b>Email: </b> {{user.email}} <br>
  <b>Country: </b> {{user.country}} <br>
  <b>Phone: </b> {{user.phone}}
</div>
```

The output is:
![Typeahead Search Network Calls](https://stackblogger.com/wp-content/uploads/2021/10/output-min.png)

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’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)](https://stackblogger.com/5-best-ways-to-optimize-angular-for-scaling/)
[7 Best Ways To Improve Angular Code (2021)](https://stackblogger.com/7-best-ways-to-improve-angular-code/)