RxJS Refactor nested map statement

Gregor Woiwode picture Gregor Woiwode · Oct 21, 2016 · Viewed 7.2k times · Source

I have a service which uses @angular/http to load data from an API. I want to create a projection of the retrieved data for my Components using this data.

Therefore I wrote the following code:

getById(id: string) {
  return this.http
    .get(`https://my-api.io/${id}`)
    .map(response => response.json())
    .map(contracts =>
      contracts.map(contract =>        # <- Nested map
        new Contract(
          contract['id'],
          contract['description']
        )
      )
    );
}

In the 6th line I have a nested map-Statement reducing the readability of my code.

Question

Can I do better? Is there an operator in RxJS which I can use instead of creating this kind of nesting?

Thanks in advance!

Answer

Marcel Hoyer picture Marcel Hoyer · Oct 22, 2016

I propose to use flatMap/selectMany to flatten your nested array into a new stream of each single array element. In a next step you can then use RxJS.map() to do the actual mapping. Finally collect all mapped array elements with RxJS.toArray()into a new observable that provides a single array event:

const stream = $http('http://jsonplaceholder.typicode.com/posts')
 .map(res => res.data)
 .flatMap(posts => posts)
 .map(post => Object.assign({}, post, { status: false }))
 .toArray();

See sample here: http://jsbin.com/vigizihiwu/1/edit?js,console

But I would also consider: is doing such limbo really necessary? If you only have one subscriber at all, map the received array there:

const stream = $http('http://jsonplaceholder.typicode.com/posts')
 .map(res => res.data);

stream.subscribe(res => {
  const posts = res.map(post => Object.assign({}, post, { status: false }));
  console.log(posts);
});