Mike Sav
Mike Sav

Reputation: 15291

Combining two observable streams in Angular2 using RxJS .flatmap

I have an Observable in a Service (called ContentService) that I have written in my Angular2 app, is looks like this (I have edited this down / reduced the content for easier reading):

@Injectable()
export class ContentService {

    constructor(private http:Http, private apiService:ApiService) {

        this.content = this.http.get('src/i18n/en.json')
            .map((res:Response) => {
                let json: {} = res.json();
                return mapData(json);
            })

        mapData() {
            // function stuff to format data
        }

Now, I wish to make a call to my injected apiService, this returns a JSON object that has the same structure as what is produced by this.content. Please note that this.content comes from a local json file and apiStream comes from a third party API / http feed. I need to concatinate (or add) the results of the apiService to the this.content observable. I think flapMap is the best way around this but I am making some syntax mistakes (if I am going about this the correct way). I was thinking of adding the new content like so

this.content = this.http.get('src/i18n/' + this.userLang + '.json')
            .map((res:Response) => {
                let json: {} = res.json();
                return mapData(json);
            })
            .flatMap(() => {
                apiService.getAllCurrentListings().subscribe(response => {
                    return mapData(response);
                })
            });

However this is producing an error so I am obviously doing something wrong. Should I want to call my API service like when not in a .flapMap I get the data I desire so I have obviously made a syntax error. How do I add the apiService data to my original this.content call results?

Many thanks in advance.

Upvotes: 0

Views: 1486

Answers (2)

Mike Sav
Mike Sav

Reputation: 15291

This is what I came up as a solution:

this.content = Observable.forkJoin(
            this.http.get('src/i18n/en.json').map((res:Response) => res.json()),
            apiService.getAllCurrentListings()
        ).map(res => {
            let tempJson:{} = Object.assign(res[0], res[1]);
            return mapData(tempJson);
        })

Upvotes: 1

Daniel Pliscki
Daniel Pliscki

Reputation: 1923

What data this.content is supposed to hold?

In your code it's getting and observable from this.http.get. If you want to get the http data response you should do this.

Injectable()
export class ContentService {

    constructor(private http:Http, private apiService:ApiService)     {

        his.http.get('src/i18n/en.json')
            .map((res:Response) => {
                let json: {} = res.json();
                return mapData(json);
            })
            .subscribe(mappedData => 
                      this.content = mappedData)

        mapData() {
            // function stuff to format data
        }
    }      

With that said, you could imagine that your second snippet is also wrong. However I wouldn't use flatMap operator in this case as I understand that apiService.getAllCurrentListings has no data dependency on the first http call. Thus, forkJoin operator could do the trick.

import {Observable} from 'rxjs/Observable'

Observable.forkJoin([
  this.http.get('src/i18n/' + this.userLang + '.json'),
  this.apiService.getAllCurrentListings()])
  .map(res => {
    this.content = this.mapData(res[0].json())
    /* again, I dind't get what this.content is supposed to hold, but we need a different variable to store the second result */
    this.content2 = this.mapData(res[1].json())
  })
  

.forkJoin groups n Observables in an array structure, thus each response must be read using an array index accordingly.

If this is not what you need, please provide the this.content definition and what it is supposed to store.

Upvotes: 0

Related Questions