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?
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