Att hämta en ordlista med objekt från en ordlista med URL:er med rxjs/typescript


Jag har ett objekt såsom

let UrlObject = { 
  'url1' : './someurl1.json',
  'url2' : './someurl2.json',..
};

Jag skulle vilja hämta alla URL:er med rxjs och låta prenumeranten veta först efter att allt har hämtats. Dessutom skulle jag också vilja att prenumeranten får ett resultatobjekt med de ursprungliga nycklarna, dvs.

let result = { 
  'url1' : fetchedObject1,
  'url2' : fetchedObject2,..
}

Det bästa jag fick är:

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/forkJoin';
import 'rxjs/add/operator/concatAll'; 
import 'rxjs/add/observable/of';

let observableBatch = [];
for (let k in urlObject) {
    observableBatch.push(
      this.http.get(templats[k]).map(
         (res) => {
             return Observable.of({[k] : res.json()})
         }
      )
    )
}
let mergedObs =Observable.forkJoin(observableBatch).concatAll();
mergedObs.subscribe((res) => {
    console.log(res);
});

Men jag får ett felmeddelande: "Egenskapen 'subscribe' finns inte på typen '{}[]'."

Hur kan jag åtgärda detta fel? Finns det ett kortare, mer elegant sätt att uppnå det jag behöver?

Svar #1

När du använder forkJoin behöver du inte använda concatAll. forkJoin prenumererar på alla käll-Observables och väntar tills alla har slutförts. Med andra ord, forkJoin sänder bara värden, inte Observables.

Hur som helst, om du inte vill skapa en array av Observable i förväg eller om källan till URL:erna inte är fast kan du till exempel göra så här:

let UrlObject = {
    'url1' : './someurl1.json',
    'url2' : './someurl2.json',
    'url3' : './someurl3.json',
    'url4' : './someurl4.json',
    'url5' : './someurl5.json',
};

function httpRequest(key, url) {
    return Observable.of(url)
        .delay(1000)
        .map(response => [key, response.split('').reverse().join('')]);
}

Observable.from(Object.keys(UrlObject).map(key => [key, UrlObject[key]]))
    .flatMap(arr => httpRequest(arr[0], arr[1]))
    .toArray()
    .map(arr => {
        const obj = {};
        arr.forEach(respArr => obj[respArr[0]] = respArr[1]);
        return obj;
    })
    .subscribe(console.log);

Detta skrivs ut till konsolen:

{ url1: 'nosj.1lruemos/.',
  url2: 'nosj.2lruemos/.',
  url3: 'nosj.3lruemos/.',
  url4: 'nosj.4lruemos/.',
  url5: 'nosj.5lruemos/.' }

Se live-demo: https://jsbin.com/hozumix/2/edit?js,console