MergeMap In Angular
In this article, we will learn about the MergeMap In Angular. The Angular MergeMap converts each value from the source observable into an inner observable, subscribes to it, and then begins emitting data from it in place of the original. For each value it receives from the Source, it creates a new inner observable. MergeMap, unlike SwitchMap, does not cancel any of its internal observables. It combines the values of all of its internal observables and returns them to the stream.
Syntax
The MergeMap operator has the following syntax.
mergeMap(project: (value: T, index: number) => O): OperatorFunction<t observedvalueof="">)
project: We use this function to alter the values emitted by the source observable. There are two arguments to the project function. The first is value, which refers to the value emitted by the source observable. The index number is the second argument. The index number starts at 0 for the first value emitted and increases by one for each item emitted after that. It's comparable to an array's index. An observable must be returned by the project function.
MergeMap Example
In order to use MergeMap in Angular, we must first import it into our Component or Service.
import { mergeMap } from 'rxjs/operators';
The code below demonstrates how to use MergeMap in Angular. We have two observables: srcObservable emitting 1,2,3,4 and innerObservable emitting 'A','B','C','D'.
let srcObservable= of(1,2,3,4) let innerObservable= of('A','B','C','D') srcObservable.pipe( mergeMap( val => { console.log('Source value '+val) console.log('starting new observable') return innerObservable }) ) .subscribe(ret=> { console.log('Recd ' + ret); }) //Output Source value 1 starting new observable Recd A Recd B Recd C Recd D Source value 2 starting new observable Recd A Recd B Recd C Recd D Source value 3 starting new observable Recd A Recd B Recd C Recd D Source value 4 starting new observable Recd A Recd B Recd C Recd D
The MergeMap's first input is the project function. The values are retrieved from the srcObservable. It produces a new observable, innerObservable, for each value it receives from the srcObservable (i.e. 1,2,3, and 4).
MergeMap subscribes to the innerObservable returned by the project method automatically. The values (A, B, C, D) are pushed to the stream by the innerObservable.
As a result, the values A, B, C, and D will be delivered four times to subscribers. For each value of the srcObservable, do this once.
MergeMap Vs Map
Value is emitted as an observable by the map operators. MergeMap produces an inner observable, subscribes to it, and emits the value of that observable as an observable.
The distinction between MergeMap and Map is seen in the following example.
By multiplying the value from the source observable by two, the Map operator below maps it to a new value. The data is subsequently written to the observable stream. The values 2, 4, 6, and 8 will be sent to subscribers.
let obs= of(1,2,3,4) //Using MAP obs.pipe( map(val => { return val*2 //Returning Value }) ) .subscribe(ret=> { console.log('Recd from map : ' + ret); }) //Output Recd from map : 2 Recd from map : 4 Recd from map : 6 Recd from map : 8
We can do the same thing with MergeMap as well. Only the way we return the new value from our project function has changed. The map returns the value as val*2, whereas the MergeMap uses the of function to return the value as observable (of(val*2)). It also subscribes to and emits the value of the newly formed observable to the stream.
let obs= of(1,2,3,4) obs.pipe( mergeMap( val => { return of(val*2) //Returning observable }) ) .subscribe(ret=> { console.log('Recd from mergeMap : ' + ret); }) //Output Recd from mergeMap: 2 Recd from mergeMap: 4 Recd from mergeMap: 6 Recd from mergeMap: 8
MergeMap combines results of inner observable
None of MergeMap's inner observables are ever canceled. It sits and waits for them to complete their tasks and emit value. It's worth noting that the inner observables may complete in a different order than the order in which they're subscribed. MergeMap is unconcerned with the order.
Using the fromEvent method, we build an observable from a button's click event in the following example. The MergeMap operator returns an inner observable delayedObs for each button click.
The delayedObs sends out five values separated by 1000 milliseconds.
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core'; import { of, from, fromEvent, interval, Observable } from 'rxjs'; import { switchMap, map, catchError } from 'rxjs/operators'; @Component({ selector: 'app-root', template: `<button button="">Click Me</button>`, }) export class AppComponent implements AfterViewInit{ @ViewChild('button',{static:true}) button; clicks$:Observable<any>; ngAfterViewInit() { this.clicks$ = fromEvent(this.button.nativeElement, 'click'); this.mergeMapExample(); } delayedObs(count:number) { return new Observable((observer) => { setTimeout(() => { observer.next(count+" A") }, 1000); setTimeout(() => { observer.next(count+" B") }, 2000); setTimeout(() => { observer.next(count+" C") }, 3000); setTimeout(() => { observer.next(count+" D") }, 4000); setTimeout(() => { observer.next(count+" E"); observer.complete() }, 5000); }) } mergeMapExample() { let obs= this.clicks$ .pipe( mergeMap(() => { this.count=this.count+1; return this.delayedObs(this.count) }) ) .subscribe(val => console.log(val)); } }
The clicks observable emits its first value when you click the button. We increment the count by one inside the MergeMap and feed it to the delayedObs. The delayedObs are subscribed to by the mergeMap. It begins by emitting values A through E, with the count prefixed.
When you click again, the mergeMap renews its subscription to the delayedObs and resumes emitting values.
The mergeMap takes all of the emitted values from all of its inner observables as they arrive and sends them to the subscribers.
Using MergeMap in Angular
The MergeMap in Angular has a number of real-world applications.
Merging values from two or more HTTP Calls
Consider the following scenario: you receive data from an observable (outer observable). To access extra data for each of those values, you should call another observable (inner observable). This is an excellent scenario for to be used in.
We have an array of dog breeds in the following example. We make an observable out of the array. This becomes our observable from the outside.
Using the free Dog API, we perform an HTTP request for each of the dog breeds produced by the outer observable to get the sub-breeds. The URL for the HTTP request is built with the dog breed information from the outer observable.
The MergeMap subscribes to all of its inner observables automatically and waits for them to finish.
of("hound", "mastiff", "retriever") //outer observable .pipe( mergeMap(breed => { const url = 'https://dog.ceo/api/breed/' + breed + '/list'; return this.http.get<any>(url) //inner observable }) ) .subscribe(data => { console.log(data) })
Without using the MergeMap, the code is as follows. Nested observable is used in the application.
of("hound", "mastiff", "retriever") .subscribe(breed => { const url = 'https://dog.ceo/api/breed/' + breed + '/list'; this.http.get<any>(url) .subscribe(data => { console.log(data) }) })
Using ForkJoin with MergeMap
For each value of the outside observable, the MergeMap creates one inside observable. The ForkJoin Operator can be used to create many inner observables.
In the following example, we send a query for a random image of a dog breed along with a list of breeds. In Angular, we'll need to send two HTTP Get requests to do this. To accomplish so, we build two observables, obs1, and obs2. The forJoin is then used to combine obs1 and obs2 and return a new observable.
MergeHTTPRequestWithFork() { //const url='https://dog.ceo/api/breed/'+hound+'/list'; of("hound", "mastiff", "retriever") .pipe( mergeMap(breed => { const url1 = 'https://dog.ceo/api/breed/' + breed + '/list'; const url2 = 'https://dog.ceo/api/breed/' + breed + '/images/random'; let obs1= this.http.get<any>(url1) let obs2= this.http.get<any>(url2) return forkJoin(obs1,obs2) }) ) .subscribe(data => { console.log(data) }) }
Conclusion
In this article, we learned what is MergeMap and how to use it in Angular using example.
I hope this article helps you and you will like it.👍
If you have any doubt or confusion then free to ask in the comment section.