Angular - HttpClient: Map Получить результат объекта метода для свойства массива

Я вызываю API, который возвращает объект JSON. Мне нужно просто значение массива для отображения в Observable. Если я вызываю api, который возвращает массив, мой сервисный вызов работает.

Ниже приведен пример кода.

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

Если возвращение - объект JSON, такой как ниже, это не удается.

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

Теперь это работает, если я просто возвращаю массив

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

Как сопоставить объект JSON Observable в наблюдаемом массиве???

Ответы

Ответ 1

Вы можете просто .map() ваш http-вызов, который является Observable, возвратить нужный тип данных.

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

Ваш httpClient.get() должен вернуть Observable, о котором вы явно заявили, что он думал Observable<Show[]>. Вы .map() - оператор, который превращает наблюдаемое в новое.

Подробнее об операторе .map(): http://reactivex.io/documentation/operators/map.html

Обновление:

Для RXJS версии 6 и выше просто используйте .pipe() для передачи оператора .map():

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

Ответ 2

Последний HttpClient, который следует использовать вместо http, не имеет метода map. Сначала вы должны импортировать его по import { map } from 'rxjs/operators'; Тогда вы должны использовать это так:

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

Ответ 3

Спасибо всем, я смог найти решение, объединив ответы от @Arun Redhu, предоставив интерфейс объекта передачи, который сервер отправляет обратно. Затем решение, предоставленное @CozyAzure, с помощью.map() преобразует одно наблюдение в правильное Наблюдаемое шоу [].

Полное решение ниже для заинтересованных.

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

  }
}

Все отлично сейчас !!! Благодарю. Поэтому, в зависимости от возвращаемых данных, я могу либо использовать напрямую, либо сопоставлять их с соответствующими наблюдаемыми.

Ответ 4

.map(res=> res['shows'] ) делает трюк

Ответ 5

Есть два подхода к этому. Вы можете использовать оператор .map из наблюдаемого для отображения одного типа наблюдаемого в другой, а второй подход - только с помощью интерфейса.

1-ый Подходы (с помощью .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);
    }

}

и во втором подходе с помощью интерфейсов обертки

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

}