web-dev-qa-db-fra.com

Angular - HttpClient: mapper le résultat d'objet de méthode avec la propriété array

J'appelle une API qui renvoie un objet JSON. J'ai juste besoin de la valeur du tableau pour mapper sur un observable. Si j'appelle api qui retourne simplement le tableau, mon appel de service fonctionne.

Voici mon exemple de 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`)
  }
}

Si le retour est un objet JSON tel que ci-dessous, cela échoue. 

// 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"
    }
  ]
}

Maintenant, celui-ci fonctionne si je retourne juste le tableau 

// 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"
    }
  ]

Comment mapper l'objet JSON Observable dans un tableau Observable ???

9
Netwobble

Vous pouvez simplement .map() votre appel http, qui est une Observable, pour renvoyer le type de données souhaité.

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

Votre httpClient.get() devrait renvoyer une Observable, que vous avez explicitement indiquée, à savoir Observable<Show[]>. Vous .map() est un opérateur qui transforme l'observable en un nouveau.

Plus d'informations sur l'opérateur .map(): http://reactivex.io/documentation/operators/map.html

11
CozyAzure

.map(res=> res['shows'] ) fait le tour

3
Sreejith sreeji

La dernière HttpClient qui devrait être utilisée à la place de http n'a pas de méthode map. Vous devriez d'abord l'importer avec import { map } from 'rxjs/operators'; Ensuite, vous devriez l'utiliser comme suit:

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

Merci à tous, J'ai trouvé une solution en combinant les réponses de @ Arun Redhu en fournissant une interface d'objet de transfert que le serveur renvoie. Ensuite, solution fournie par @CozyAzure en utilisant le fichier .map () pour transformer un observable en observable correct []. 

Solution complète ci-dessous pour ceux que ça intéresse.

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); 

  }
}

Tout va bien maintenant !!! Merci . Donc, en fonction des données renvoyées, je peux utiliser directement ou mapper le bon Observable dont j'ai besoin. 

1
Netwobble

Il existe 2 approches pour ce faire. Vous pouvez utiliser l’opérateur observable .map pour mapper un type d’observable en un autre et la seconde approche inclut uniquement l’aide d’interface. 

1ères approches (avec l'aide de .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);
    }

}

et dans la 2ème approche à l'aide d'interfaces de wrapping

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')
    }

}
0
Arun Redhu