Angular: map response from service

15,937

Yes, you are calling the service right.

Regarding map, the best way to think of it in your case is that RxJS's map iterates over the requests as they come in and transforms them as a whole. Every service call you make will return one response. If your intent is to transform this response, then yes, use the RxJs map operator as above and perform whatever transformation you require on the server received data object. Here's an example that transforms your server retrieved data object from a hash to an array by using the RxJs map operator:

// Returned data by the api call
// {
// "1":{
//      "id":"1",
//      "name":"Anna"
//     },
// "2":{
//      "id":"2",
//      "name":"Martin"
//     }
// }

fetchInfo(): Observable<Info> {
 const url = "/assets/info-response.json";
 return this.httpClient.get<Info>(url)
  .map((data: Info) => {
    // in here, data is equal to your returned JSON above
    // So, if you wish to turn this into an array
    
    const transformedData = Object.keys(data).map(key => data[key]);
    
    // as you return this output, any operator applied below,
    // as well as the data that will reach your subscribe resolver
    // will look like:
    //
    // [
    //  { "id":"1", "name":"Anna" }
    //  { "id":"2", "name":"Martin" }
    // ]
    
    reuturn transformedData;
  });
}

// As for processing the response now that it is an array...

fetchInfo().subscribe(data => {
  this.infodata = data.map(value => ({ ...value, city: 'Amsterdam' }));
  
  // your infodata object will now look like this:
  //
  // [
  //  { "id":"1", "name":"Anna", "city": "Amsterdam" }
  //  { "id":"2", "name":"Martin", "city": "Amsterdam" }
  // ]
});

If, on the other hand, your are happy with the response as it is returned by the server, there is no need to apply the map operator on it as it is redundant. Your service call will then become simply:

return this.httpClient.get<Info>(url);

Some useful reference: Object.keys(), Array.map() method used to transform your result array, RxJs's map operator used on your api calls.

And a simple, straightforward solution with no demo code, that does the exact same thing as the code above:

fetchInfo(): Observable<Info> {
 return this.httpClient.get<Info>("/assets/info-response.json");
}

fetchInfo().subscribe(data => {
  this.infodata = data.keys(key => data[key]).map(value => ({ ...value, city: 'Amsterdam' }));
});

Be mindful, as of RxJs 5, the map operator is no longer applied directly on the observable, but via piping.

Does this help?

Edit:

As Object.values is not yet fully supported, I used Object.keys instead.

Edit 2:

Added a straightforward solution, without demo code to explain RxJs's map

Share:
15,937
Anna
Author by

Anna

Updated on June 09, 2022

Comments

  • Anna
    Anna almost 2 years

    I have been working on angular4 for a while, handling JSON response from service. But today I observed my service returning me response like this.

    info-response.json

    {
    "1":{
         "id":"1",
         "name":"Anna"
        },
    "2":{
         "id":"2",
         "name":"Martin"
        }
    }
    

    I did google it and found it to be a map but how do I read this type of response, I am not able to iterate it. I did write a service as below.

    model is Info.ts

    export interface Info{
      id: string;
      name: string;
    }
    

    ts file is:

    infoData: Info;
    this.groupService.fetchInfo().subscribe(data => {
     this.infoData = data;
     // how to iterate this.infoData
    });
    

    service is:

    fetchInfo(): Observable<Info>{
     const url = "/assets/info-response.json"; //as of now I am working on hard coded json as I dont know my map logic is correct of not
     //const url = "/info/getInfo";
     return this.httpClient.get<Info>(url).map(function (data => Info){
       return data;
      });
    }
    

    I do not have any understanding of map and I am not even sure that is my piece of code correct or not. I did not try hitting the service as of now and I am working on the hard coded JSON, as mentioned above. Please guide me:

    Is my way of calling service right, handling map? How to iterate this type of response?

  • Anna
    Anna over 5 years
    I tried, but when I did data.values() it is giving me error "Property 'values' does not exist in info-response.json. Can you help on this?
  • alexc
    alexc over 5 years
    @Anna Ah, alright, this is because your browser language lever does not support it. I'm updating the response.
  • Anna
    Anna over 5 years
    No no its not the error that I am getting in console, I am getting error in my visual studio at below line: const transformedData = data.values();...... error says Property values doesnot exist on type info-response
  • alexc
    alexc over 5 years
    @Anna I've updated the response. Please not, using the map operator in my example is only there for demo purposes. You can just as easily skip using the map operator to transform your response into an array and move all that code into your subscribe resolver. FYI
  • alexc
    alexc over 5 years
    As stated on the MDN pages, Object.values is standard only in the ECMA2017 specification. Unless VisualStudio is set up to interpret Javascript with the ECMA2017 language level, it will indeed show you that error. In any case, the updated solution using Object.keys is safer for the time being, it might be that not all browsers have implemented the ECMA2017 language spec, although I don't know this for sure.
  • alexc
    alexc over 5 years
    @Anna I've added a 2nd solution with simple, straightforward, example-free code that solves your problem.
  • alexc
    alexc over 5 years
    @Anna if my answer solved your problem, please mark it as accepted or, at the very least, upvote it