0
votes

Every time I think I understand Observables, I don't quite understand Observables. So consider this code I use in my Angular 4 app:

// this returns the url to our bitbucket server. the uriService returns
// an Observable<string>
return this.uriService.getBitBucketUrl(path)
  
  // I expect exactly one result, no more, no less, otherwise exception        
  .single() 

  // somehow I still need a flatMap here, to supply the url value into the nested observable
  .flatMap((url: string) => {
    
    // we now have the bitbucket url, use it to get json from it.
    return this.httpService.getJson(url)
      
     // map the result and flatten it to an array
     .flatMap((json: HttpResponse<any>): Array<any> => json.body.values)

     // map each value into a more managed model
     .map<any, BitbucketModel>((value: any) => {
        // create and return BitBucketModel here based on json
 })
});

I hope I explain the code well enough, so the essence of it is that I don't want to use 'subscribe' anywhere. because I use the async pipe I want observables all the way down. But when I use single() and then I have to flatMap it otherwise it gives me an error because I can't return Observable < Observable < BitBucketModel > >.

EDIT I'm sorry if I didn't make it clear enough what I was asking. My scenario is that I basically need a config setting where my actual http request is based on. So I must retrieve that setting and based on that settings do that actual http request.

1
I didnt get two things : 1) Why use single 2) what are you asking exactly - Vamshi
@Skeptor, Single(), according to the docs, expects a single result from and obs, and that's exactly what I want. If it's not a single value it throws an exception. If you have additional insight, please let me know. Further; I'm sorry my question wasn't completely clear. I'll update it. - Gerben Rampaart
No problem, are you getting any error . Did I answer your question - Vamshi
@Skeptor you definitely clarified map vs flatMap. I'm still unsure as to why the output of a single() requires flattening because it can only emit a single result. - Gerben Rampaart
But its still a stream right . The core concept of rx is "everything is a stream". Even if its a single item, its considered as a stream. This makes it easy to chain and reuse. It's a paradigm shift , you just need to get the 'aha' moment :) - Vamshi

1 Answers

2
votes

If I understand it correctly, you are asking why flatMap . Let me try to explain.

map converts input to output synchronously . So it takes each item transforms it to something else replaces old item with new one. This process is synchronous.

flatMap also does replace but instead does it asynchronously .

flatMap takes an item, converts it to an Observable and output of the new Observable steam is put in place of original item.

So flatMap can be used in these two instance ( might be more applications) :

  1. if output is asynchronous ( ex. url to http call response )
  2. if output is Observable ( ex. Array to independent elements )

ex:

...'string1'... 'string2'... => 
 ...Output(Observable created from string1)...
 ...Output(Observable created from string2)...

In your case :

input : string ( url )

output : json from asynchronous http call .

So, you have to use flatMap . Its not related to single()

Another point:

In your example :

.flatMap((json: HttpResponse<any>): Array<any> => json.body.values)

this is a synchronous transformation . You are taking an object and synchronously returning another object . So it need not be a flatMap . You can just say

.map((json: HttpResponse<any>): Array<any> => json.body.values)

In fact your code should give an error as flatMap expects an Observable as return type but you are returning an object.