0

I can't understand why the below code doesn't work as expected.

    public GetX(): Observable<MyDataType> {
    return this.http.get('http://localhost:64113/api/endpoint')
        .map((r: Response) => r.json())
        .map((r) => r.someProperty)
        .catch(error => Observable.throw(error));
}

The problem is the second map function only gets called once even though I'm returning an array from the .Net Core WebAPI endpoint. It looks like:

[{}, {}, {}, {}...]

Shouldn't map iterate over every element in the array being passed back from the server?

Below is the result of the console.log

(124) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object…]
6
  • Put the code for the MyDataType Commented Jul 19, 2017 at 11:18
  • I've made a change that demonstrates more closer to what I'm actually doing. Commented Jul 19, 2017 at 11:26
  • Having done some more testing the problem is the second map function does not see the argument (r) as an element of an array, r is still an array at the point the second map function is called Commented Jul 19, 2017 at 11:30
  • 2
    Is the JSON object returned by you backend an array of objects or an object? If its an array, how do you think to map a single property of every element to only one object? the return type of your function should be on that case an array to Commented Jul 19, 2017 at 11:31
  • From the server an array of objects is returned, I don't want to map to a single element. I want to take one property from each element of the array and return an array of those properties. e.g [{property:1}, {property:2}, {}, {}...] Commented Jul 19, 2017 at 11:52

3 Answers 3

1

The problem is the second map function that you are calling. Map applies a transformation to a stream of data and should return the transformed elements.

Currently the 2nd map consumes the array of POJOs returned by your webapi but doesnt pass them back again to the stream flow.

Assuming that MyDataType is a typescript interface and contains the matching properties of the returned JSON object from your webapi, you could use the following to print the server response:

return this.http.get('http://localhost:64113/api/endpoint')
        .map(r => r.json())
        .do(r => console.log(r))
        .catch(error => Observable.throw(error));

UPDATE: if you want to map a property of every element in the array, you should use mergeMap

 return this.http.get('http://localhost:64113/api/endpoint')
            .map(r => r.json()) // map to json body
            .mergeMap(r => r) // flatten array
            .map(e => e.property) //map singular objects to a property
            .catch(error => Observable.throw(error));

MergeMap will flatten the array by mapping every singular POJO to one of its properties. In this case the return type of your function is trully accurate anymore.

You can find more info about the operator here

Sign up to request clarification or add additional context in comments.

3 Comments

The OP code is correct, by not using the {} indide the callback code the value is automatically returned
Not sure what you meant, but yeah, that would be related to arrow expressions. Anyways, the op edited the original question that included a console log...Ill updated my answer
I get: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
0

If you need to iterate over an array returned by an ajax call, you should wrap it inside an Observable.from function. You do need another map after the json one, a map that does not return a value, but an observable. In such case use a flatMap.

//code omitted for brevity
.map( r : Response => r.json() )
.flatMap((obj: any) => Observable.from(obj) )

After this point the Observablel of array becomes an Observable of single values. However i have no clue about the type you have provided, and cant see if the type is a wrapper around an array or not

4 Comments

But why do none of the examples online not do this?
This is a pretty basic example, more common than you think, however by not knowing the client of the observable i cannot say it's the right approach. For instance, the client of the observable ( its subscriber ) just need an array of values to render them, or the template is the consumer, and it is using an async pipe. All is based on which kind of values the client it is intrested in, and many operators can be used to map the observable output for specific needs
Why do I need to do Observable.from(obj) ?
The value you get from calling the http.get function is an observable of a response, the response is a single value. If you need a stream that emit multiple times, you can either create a custom one or use the Observable.from operator
0

I want to take one property from each element of the array and return an array of those properties. e.g [{property:1}, {property:2}, {}, {}...]

Then I would suggest you do it like the following, where we use map on the array and assign the property you want to a new object, with Object.assign

public GetX(): Observable<MyDataType> {
  return this.http.get('http://localhost:64113/api/endpoint')
    .map((r: Response) => r.json().map((x:any) => Object.assign({propertyName: x.property})))
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.