2
votes

I try to fetch data from 3 different REST end points. The data model consists of main data and has advanced Array with 2(might be more in the future) Objects. I want to inject an Array with options into each of advanced Objects, based on REST endpoint specified in each of them. Everything works and is returned from Observable as Object, except appended options, that come as Observables.

Simplified data:

{
 simple: {
   param: "searchQuery",
 },
 advanced: [
  {
   param: "food",
   optionsModel: {
     url: "http://address.com/food",      
     }
  },
  {
   param: "drinks",
   optionsModel: {
     url: "http://address.com/drinks",
     }
   }
  ]
}

food and drinks have the same structure consisting of Objects with name and id:

 {
  data: [
   {
     name: "DR1",
     id: 1
   },
   {
     name: "DR2",
     id: 1
   },
   ...
  ]
 }

In my data model I don't have options[] array, so I inject it manually. Service:

 searchConfiguration$: Observable<SearchConfiguration> = this.http
  .get(this._configURL)
  .map((config) => {
      let configuration = config.json();
      let advancedArray = configuration.advanced;

      if(advancedArray) {
        advancedArray.forEach(advanced => {
          advanced.options = [];
          advanced.options = this.http.get(advanced.optionsModel.url)
             .map((r: Response) => r.json().data
        })
      }
    return configuration;
  })

Parent component:

getSearchConfig() {
  this.searchConfiguration$ = this._bundlesService.searchConfiguration$;
} 

Then I have async pipe in the html to subscribe to Observable. How can I get my options appended to advanced as actual Arrays and not as a stream?

Edit - Solution

Thanks to martin's answer, the solution is to flatten both streams and connect them in the end with forkJoin()

  searchConfiguration$: Observable<SearchConfiguration> = this.http
  .get(this._configURL)
  .map((config) => config.json())
  .concatMap((configuration) => {
      let observables = configuration.advanced.map((advanced) => {
        return this.http.get(advanced.optionsModel.url)
          .map((r: Response) =>  r.json().data)
          .concatMap((options) => advanced.options = options)
      });
    return Observable.forkJoin(observables, (...options) => {
      return configuration;
    })
  });
1

1 Answers

1
votes

I didn't test it but I think you could you something as follows:

searchConfiguration$: Observable<SearchConfiguration> = this.http
  .get(this._configURL)
  .map((config) => config.json())
  .concatMap(configuration => {
    var observables = configuration.advanced.map(advanced => {
      return this.http.get(advanced.optionsModel.url)
         .map((r: Response) => r.json().data);
    });

    return Observable.forkJoin(observables, (...options) => {
      configuration.options = options;
      return configuration;
    });
  })