Angular + RxJS map

By Arvind Rai, November 12, 2018
This page will walk through Angular and RxJS map operator example. RxJS map applies a given function to each element emitted by the source Observable and emits the resulting values as an Observable. RxJS map is imported from rxjs/operators. The map is a pipeable operator. In RxJS 6, Observable uses pipeable operators using its pipe instance method. RxJS map can be used with other pipeable operators. RxJS map is different from JavaScript array map. Here on this page we will provide RxJS map operator example. We will also provide error handling using retry and catchError operators with map. Now find the complete example step by step.

Technologies Used

Find the technologies being used in our example.
1. Angular 7.0.0
2. Angular CLI 7.0.3
3. TypeScript 3.1.1
4. Node.js 10.3.0
5. NPM 6.1.0
6. RxJS 6.3.3

Observable and map

map is a RxJS pipeable operator. map applies a given function to each element emitted by the source Observable and emits the resulting values as an Observable. map is imported as following.
import { map } from 'rxjs/operators'; 
map is used with pipe which is an instance method of Observable.
Suppose we have an Observable of a string that contains comma separated names.
getStdNames(): Observable<string> {
   return of("Mahesh, Krishna, Ram");
} 
Now we will map this string into array and return result into Observable of array of names.
stdNames$: Observable<string[]>; 
getStdNames() { 
 this.stdNames$ = this.bookService.getStdNames().pipe(
    map(res => res.split(","))
 ); 
}
We can iterate stdNames$ as following.
<ul>
  <li *ngFor="let name of stdNames$ | async" >
    {{name}}
  </li>
</ul> 
We can also subscribe the Observable instance.
this.bookService.getStdNames().pipe(
     map(res => res.split(","))
)
.subscribe(names=> names.forEach(name => console.log(name))); 

Using map with Other RxJS Operators

Here we will use map with filter and scan. Suppose we have following data.
getNumbers(): Observable<number> {
   return of(1, 2, 3, 4, 5, 6, 7); // Synchronously data will be emitted.
} 
Now find the code to use map with filter and scan operators.
calcData() {
  this.bookService.getNumbers().pipe(
     filter(n => n % 2 === 1),
     map(n => n + 10),
     scan((sum, n) => sum + n)
  )
  .subscribe(result => console.log(result));
} 
Output will be 11, 24, 39, 56. The result of getNumbers() will be first processed by filter operator, then map() and then scan.

Error Handling: map with retry and catchError

We handle error using retry and catchError operators. In case of failure, retry operator retries to fetch record for the given number of times. catchError operator caches the error thrown by any operator, if there is any error. Find the code snippet to use map operator with error handling.
getCountryStates() {
 this.mapDemoService.getCountry().pipe(
   retry(2),
   map(country => country.getCountryStates()),
   catchError(err => {
	console.error(err);
	return of([]);
   })
 )
 .subscribe(res => this.countryStates = res); 
} 

JavaScript Array map vs RxJS map

Suppose we have following array.
let cities = ["Varanasi", "Mathura", "Ayodhya"]; 
a. JavaScript Array map applies a given function to each element of the array and returns the modified array.
cities.map(c => "Holy "+ c)
.forEach(el => console.log(el)); 
JavaScript Array map will iterate the array and apply given function to each element and finally returns array with modified data. Find the output.
Holy Varanasi
Holy Mathura
Holy Ayodhya 
b. RxJS map operator applies a given function to each element emitted by source Observable and returns Observable instance with modified data.
of(cities).pipe(
    map(dataArray => dataArray.join(", "))
).subscribe(res => console.log(res)); 
Here RxJS map will receive an array emitted by source Observable but this RxJS map will not iterate the array. The given function will be applied on the array. Here we are applying join function on the array and finally RxJS map will return the Observable instance with modified data. Find the output.
Varanasi, Mathura, Ayodhya 

Complete Example

map-demo.component.ts
import { Component, OnInit } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map, filter, scan, retry, catchError } from 'rxjs/operators';
import { MapDemoService } from './map-demo.service';

@Component({
   selector: 'app-map-demo',
   templateUrl: './map-demo.component.html'
})
export class MapDemoComponent implements OnInit { 
   stdNames$: Observable<string[]>; 
   countryName$: Observable<string>;
   countryStates: string[];

   constructor(private mapDemoService: MapDemoService) { }
   
   ngOnInit() {
      this.getStdNames();
      this.calcData();      
      this.getCountryName();
      this.getCountryStates();

      let cities = ["Varanasi", "Mathura", "Ayodhya"];

      //Using JavaScript Array map
      cities.map(c => "Holy "+ c)
      .forEach(el => console.log(el));
  
      //Using RxJS map
      of(cities).pipe(
        map(dataArray => dataArray.join(", "))
      ).subscribe(res => console.log(res)); 

      
   }

   //Using map 
   getStdNames() {
    this.stdNames$ = this.mapDemoService.getStdNames().pipe(
      map(res => res.split(","))
    );
    
    this.mapDemoService.getStdNames().pipe(
      map(res => res.split(","))
    )
    .subscribe(names=> names.forEach(name => console.log(name)));
   }	

   //Using filter, map and scan
   calcData() {
    this.mapDemoService.getNumbers().pipe(
      filter(n => n % 2 === 1),
      map(n => n + 10),
      scan((sum, n) => sum + n)
    )
    .subscribe(result => console.log(result));
   }
   //Using map and catchError
   getCountryName() {
    this.countryName$ = this.mapDemoService.getCountry().pipe(
      map(country => country.getCountryName()),
      catchError(err => {
        console.error(err);
        return of("");
      })
    );
   }

   //Using retry, map and catchError
   getCountryStates() {
    this.mapDemoService.getCountry().pipe(
      retry(2),
      map(country => country.getCountryStates()),
      catchError(err => {
        console.error(err);
        return of([]);
      })
    )
    .subscribe(res => this.countryStates = res); 
   }
} 
map-demo.component.html
<b>Student Names</b>
<ul>
  <li *ngFor="let name of stdNames$ | async" >
    {{name}}
  </li>
</ul>

<b>Country Name</b>
<div *ngIf="countryName$ | async as myCountryName">
  {{myCountryName}} 
</div>

<b>Country States</b>
<ul>
  <li *ngFor="let state of countryStates" >
    {{state}}
  </li>
</ul> 
map-demo.service.ts
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { MyCountry } from './my-country';

@Injectable({
    providedIn: 'root'
})
export class MapDemoService {
    getNumbers(): Observable<number> {
      return of(1, 2, 3, 4, 5, 6, 7);
    }
    getStdNames(): Observable<string> {
      return of("Mahesh, Krishna, Ram");
    }	
    getCountry(): Observable<MyCountry> {
      return of(new MyCountry());
    }
} 
my-country.ts
export class MyCountry {
   getCountryName() {
       return "India";
   }  
   getCountryStates() {
       return ["UP", "MP", "Assam", "Kerla"];
   }
} 
app.component.ts
import { Component } from '@angular/core';

@Component({
   selector: 'app-root',
   template: `
	<app-map-demo></app-map-demo>
    `
})
export class AppComponent { 
} 
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent }  from './app.component';
import { MapDemoComponent }  from './map-demo.component';
import { MapDemoService } from './map-demo.service';

@NgModule({
  imports: [     
      BrowserModule,
      HttpClientModule,
      FormsModule,
  ],
  declarations: [
      AppComponent,
      MapDemoComponent
  ],
  providers: [
  ],
  bootstrap: [
      AppComponent
  ]
})
export class AppModule { } 

Run Application

To run the application, find the steps.
1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Access the URL http://localhost:4200
Find the print screen of the output.
Angular + RxJS map

References

RxJS Observable
Angular: The RxJS library
Pipeable Operators

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI









©2023 concretepage.com | Privacy Policy | Contact Us