user
user

Reputation: 568

Angular map or mergeMap

I have a simple JSON file which returns an array of objects in format:

[
    {
        "id": 1,
        "url": "file/abc.txt"
    },
    {
        "id": 2,
        "url": "file/def.txt"
    }
]

I am accessing the service as given below:

this.http.get("json-url")
.map((response) => response.json())
.filter((file) => file.id === 1)

It doesn't work anything. However if I use mergeMap instead, it works fine.

this.http.get("api-url")
.mergeMap((response) => response.json())
.filter((file) => file.id === 1)

I have used map operator earlier and it worked. However it is not working here. Please let me know if I am mistaking anything while using map operator.

Please note- I am using angular 6.

Upvotes: 0

Views: 2033

Answers (3)

driver_by
driver_by

Reputation: 1705

Important to understand here is that this.http.get("json-url") returns an observable. It won't be executed until you subscribe. You must subscribe to send the request.

this.http.get("json-url") .map((response) => response.json()) .filter((file) => file.id === 1) .subscribe(theResultAfterMapAndFilter => console.log(theResultAfterMapAndFilter));

The reason why mergeMap works is that it subscribes to the source observable internally (if I'm not mistaken).

Upvotes: 1

SiddAjmera
SiddAjmera

Reputation: 39482

If you're running Angular 6, it's really recommended to use HttpClient as Http is deprecated. Now since you'd be using HttpClient you won't need to call .json method on the response as that is something that HttpClient takes care of implicitly.

Also, since Angular 6 uses Rxjs 5.5 or later, you can't directly chain the operators like map and pipe to an Observable. You'll have to call the pipe function on an Observable value and add the list of operators that you want to you separated by a ,.

import { HttpClient } from '@angular/common/http';
import { map, filter } from 'rxjs/operators';

...

constructor(private http: HttpClient) {}

...

return this.http.get("json-url")
  .pipe(filter((file) => file.id === 1));

Here, I'm returning the Observable so that I can subscribe to it from the place I'm calling the function that is wrapping this piece of code.

To make sure that HttpClient works correctly, you'll also have to import HttpClientModule in your @NgModule file and add it to the imports array.

Upvotes: 1

pgreen2
pgreen2

Reputation: 3651

I have an answer for why map isn't working, but i'm not entirely sure why mergeMap is working. The object returned from response.json() is any list. So the filter should handle the full list. Not the individual elements of the list. The list has not property of id so nothing matches. Even though the parameter in filter is called file, it should be files. I believe the following will work with map:

this.http.get("json-url")
.map((response) => response.json())
.filter((files) => files.filter((file)->file.id === 1));

However, you would get a list back. If you really want a single file, you could add in another map:

this.http.get("json-url")
.map((response) => response.json())
.filter((files) => files.filter((file)->file.id === 1))
.map(files=> files[0]);

With all of that said, I think the reason mergeMap worked might be some older quirk of rxjs. My unverified guess is that list returned from the anonymous function is being converted into an observable by mergeMap. That seems a bit fishy, but could be possible. The older rxjs API seemed to try to make things work even if it probably shouldn't.

Upvotes: 0

Related Questions