Angular - HttpClient: Map Get method object result to array property

75,803

Solution 1

You can simply .map() your http call, which is an Observable, to return the data type that you want.

findAllShows(): Observable<Show[]> {
    return this.http
        .get(`${someURL}/shows`)
        .map(result=>result.shows)
}

Your httpClient.get() should return an Observable, which you have explicitly stated it thought Observable<Show[]>. You .map() is an operator that transform the observable into a new one.

More on .map() operator: http://reactivex.io/documentation/operators/map.html

Update:

For RXJS version 6 and above, simply use .pipe() to pipe the .map() operator:

findAllShows(): Observable<Show[]> {
    return this.http
        .get(`${someURL}/shows`)
        .pipe(map(result=>result.shows))
}

Solution 2

Latest HttpClient which should be used instead of http has no map method. You should first import it by import { map } from 'rxjs/operators'; Then you should use it this way:

this.http.get(`${someURL}/shows`).pipe(
        map(res => res['shows'])
    )

Solution 3

Thanks All, I was able to find solution by combining responses from @ Arun Redhu by providing a transfer object interface that the server sends back. Then solution provided by @CozyAzure by using the .map() to transform one Observable to the correct Observable Show[].

Full Solution below for those interested.

import {Observable} from 'rxjs/Observable';
import {Contact} from '../models/show';
import {environment} from '../../../environments/environment';
// Use the new improved HttpClient over the Http
// import {Http, Response} from '@angular/http'; 
import {HttpClient} from '@angular/common/http';

// Create a new transfer object to get data from server
interface ServerData {
  shows: Show[];
}

@Injectable()
export class ShowsService {

  constructor(private http: HttpClient ) { }

// want Observable of Show[]
  findAllShows(): Observable<Show[]> {  
    // Request as transfer object <ServerData>
    return this.http
      .get<ServerData>(`${apiURL}/shows`)
     // Map to the proper Observable I need 
      .map(res => <Show[]>res.shows); 

  }
}

All great now!!! Thanks . So depending on data returned I can either use directly or map to proper Observable I need.

Solution 4

.map(res=> res['shows'] ) does the trick

Solution 5

There are 2 approaches of doing this. You can use .map operator form the observable to map one type of observable into another and second approach includes just with the help of interface.

1st Approaches (with the help of .map)

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/map';

interface ItemsResponseObj {
    id: string,
    modified: string,
    name: string
}

interface ItemsResponse {
    shows: Array<ItemsResponseObj>;
}

@Injectable()
export class AppService {

    constructor(private http: HttpClient) { }

    getData(): Observable<ItemsResponseObj[]> {
        return this.http.get<ItemsResponse>('api/api-data.json')
            .map(res => res.shows);
    }

}

and in the 2nd approach with the help of wrapping interfaces

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { Observable } from 'rxjs/Observable';

interface ItemsResponseObj {
    id: string,
    modified: string,
    name: string
}

interface ItemsResponse {
    shows: Array<ItemsResponseObj>;
}

@Injectable()
export class AppService {

    constructor(private http: HttpClient) { }

    getData(): Observable<ItemsResponse> {
        return this.http.get<ItemsResponse>('api/api-data.json')
    }

}
Share:
75,803
Netwobble
Author by

Netwobble

Updated on July 09, 2022

Comments

  • Netwobble
    Netwobble almost 2 years

    I am calling an API that returns a JSON Object. I need just the value of the array to map to a Observable . If I call api that just returns the array my service call works.

    Below is my sample code ..

    // my service call ..
    import { Injectable } from '@angular/core';
    import {Observable} from 'rxjs/Observable';
    import {Show} from '../models/show';
    import {HttpClient} from '@angular/common/http';
    
    @Injectable()
    export class MyService {
    
      constructor(private http: HttpClient ) { }
    
    
      findAllShows(): Observable<Show[]> {
        return this.http
          .get<Show[]>(`${someURL}/shows`)
      }
    }
    

    If the return is a JSON Object such as below this fails..

    // Service API that FAILS ...
    {
      "shows": [
        {
          "id": "123f9165-80a2-41d8-997a-aecc0bfb2e22",
          "modified": "2017-08-13 15:54:47",
          "name": "Main Show1"
        },
        {
          "id": "456f9165-80a2-41d8-997a-aecc0bfb2e22",
          "modified": "2017-08-14 15:54:47",
          "name": "Main Show2"
        },
        {
          "id": "789f9165-80a2-41d8-997a-aecc0bfb2e22",
          "modified": "2017-08-17 15:54:47",
          "name": "Main Show3"
        }
      ]
    }
    

    Now this one works if I just return the Array

    // Service API that Works ...
    [
        {
          "id": "123f9165-80a2-41d8-997a-aecc0bfb2e22",
          "modified": "2017-08-13 15:54:47",
          "name": "Main Show1"
        },
        {
          "id": "456f9165-80a2-41d8-997a-aecc0bfb2e22",
          "modified": "2017-08-14 15:54:47",
          "name": "Main Show2"
        },
        {
         "id": "789f9165-80a2-41d8-997a-aecc0bfb2e22",
          "modified": "2017-08-17 15:54:47",
          "name": "Main Show3"
        }
      ]
    

    How do I map the JSON object Observable into an Array Observable???

  • Netwobble
    Netwobble over 6 years
    I tried and got error... Property 'shows' does not exist on type 'Response' .
  • CozyAzure
    CozyAzure over 6 years
    @Netwobble No, do not type cast it to type Response. See my edit.
  • Arun Redhu
    Arun Redhu over 6 years
    'map' function is still not available for httpClient
  • CozyAzure
    CozyAzure over 6 years
    @ArunRedhu httpClient.get() should return an Observable, which us explicitly stated throughObservable<Show[]>. The .map() is an operator that transform the observable into a new one.
  • Jota.Toledo
    Jota.Toledo over 6 years
    creating a new interface just to wrap the data, and then unwrap it is not the best approach
  • Jota.Toledo
    Jota.Toledo over 6 years
    get('') with no type parameter should return Observable<Object>. Try with .map(res => res['shows'])
  • Jota.Toledo
    Jota.Toledo over 6 years
    lol, why <Show[]>? The .shows property in the map already has the wished type
  • Jota.Toledo
    Jota.Toledo over 6 years
    @CozyAzure this should be the accepted answer, sad to see that OP overlooked this
  • rollstuhlfahrer
    rollstuhlfahrer about 6 years
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
  • Tremmillicious
    Tremmillicious almost 6 years
    Yeah More info to why res.shows doesn't work but this works
  • Robert Brisita
    Robert Brisita almost 5 years
    Make sure to have "suppressImplicitAnyIndexErrors": true, in your tsconfig.json file to suppress error TS7015.
  • Mrunalini
    Mrunalini over 4 years
    I tried the above approach. I am getting the data in the service but not in the component. Can you show me how to call the service in the component?Thanks in advance