Обработка сложного объекта по http get в Angular 6 - PullRequest
0 голосов
/ 25 мая 2018

Я не понимаю, как обращаться с объектом, на который я подписываюсь.Объект имеет следующую структуру:

{
  data:{
       date: "2018-02-20 13:10:23",
       text: "Описание",
       id: 1,
       items: [
              0: {
                 date: "2018-02-20 13:10:23",
                 text: "Описание",
                 images: [
                         0: "image1.jpg",
                         1: "image2.jpg"
                         ],
                 name: "Изображения",
                 type: "images"
                 },
              1: {
                 date: "2018-02-20 13:10:23",
                 text: "Описание",
                 image: null,
                 type: "video",
                 url: "https://www.youtube.com/embed/v64KOxKVLVg"
                 }
              ]
       }
}

Я подаю апелляцию через сервис:

import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
@Injectable()
export class VideoService {
    constructor(private http: HttpClient) {}

    getVideoTape() {
        return this.http.get(`http://ip_adress/api/v1/mixed_galleries/1`);
    }
}

Есть модель интерфейса:

export class VideoListModel {
    constructor(
        public created_at: string,
        public description: string,
        public id: number,
        public items: any[],
        public name: string
    ) {}
}

И явыполните обработку в компоненте:

import {Component, OnDestroy, OnInit} from '@angular/core';
import {Observable, Subscription} from 'rxjs';
import {filter} from 'rxjs/operators';
import {VideoService} from '../shared/services/video.service';
import {VideoListModel} from '../../shared/models/video-list.model';

@Component({
  selector: 'app-video-index',
  templateUrl: './video-index.component.html',
  styleUrls: ['./video-index.component.scss']
})

export class VideoIndexComponent implements OnInit, OnDestroy {
    private videoTape = [];
    private _subscription2: Subscription;

    constructor( private videoService: VideoService ) { }

  ngOnInit() {
      this._subscription2 = this.videoService.getVideoTape()
          .subscribe((data: VideoListModel[]) => {
          this.videoTape = data;
          console.log(this.videoTape);
      });
  }

    ngOnDestroy() {
        this._subscription2.unsubscribe();
    }

}

Задача - сделать выбор из объектов по типу: «видео».Через AJAX + jQuery делал это без проблем, а в Angular я относительно новичок.Вчера откопал кучу видео уроков, но нигде не было примеров фильтрации таких сложных объектов.

Конструкция:

this._subscription2 = this.videoService.getVideoTape()
          .pipe(filter((data: VideoListModel[]) => data.items.type === 'video'))
          .subscribe((data: any) => {
              this.videoTape = data.data;
              console.log(this.videoTape);
          });

не работает.В результате возникает ошибка, в которой говорится, что «свойство 'items» не существует для типа «VideoListModel []».Интуитивно я понимаю, что дело, скорее всего, в интерфейсе, но я не могу понять, как изменить интерфейс так, чтобы фильтрация работала правильно.Если кто-то сталкивался с фильтрацией сложных объектов, скажите, пожалуйста, как решить эту проблему.

Ответы [ 4 ]

0 голосов
/ 25 мая 2018

Включите изменения, предложенные @Piero, и ваша служба не возвращает никаких наблюдаемых.

import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
@Injectable()
export class VideoService {
    constructor(private http: HttpClient) {}

    getVideoTape():Observable<any>  {
        return this.http.get(`http://ip_adress/api/v1/mixed_galleries/1`);
    }
}
0 голосов
/ 25 мая 2018

У вас нет массива VideoModels, но есть массив items в объекте.Передача всего содержимого в фильтр позволяет фильтровать элементы из массивов, но у вас есть объект.Вы можете попробовать следующий обходной путь:

Создайте подобный интерфейс

interface Item {
  date: Date;
  text: string;
  images: string[];
  name: string;
  type: string;
}

export interface VideoModel {
  data: {
    date: Date;
    text: string;
    id: number;
    items: Item[];
  }
}

Затем вы можете использовать HttpClient в своей службе следующим образом

import { Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
[...]

getVideoTape(): Observable<VideoModel> {
  return this.http.get<VideoModel>(url).pipe(
    map(model => {
      const items = model.data.items.filter(item => item.type === 'video');
      model.data.items = items;
      return model;
    }),
    catchError(error => console.error(error))
  );
}

Обратите внимание на вашмассив изображений, так как он недопустим json, string []?Не лучше ли отфильтровать типы серверов для уменьшения трафика?

0 голосов
/ 25 мая 2018

Вы говорите, что data - это array типа VideoListModel, у массива причин нет свойства items.То, что вы сделали, похоже на Array.items.type, что не имеет смысла.Возможно, есть и более причудливые решения, но попробуйте сопоставить ваш массив результатов с наблюдаемой, где вы сможете использовать свои фильтры.

this._subscription2 = this.videoService.getVideoTape()
.pipe(
    map(data => from(data).pipe(filter((d: VideoListModel) => d.items.type === 'video')))
    tap(data => data.subscribe(d => {
        this.videoTape.push(d);
    }))
).subscribe();

Дополнительно отображайте данные таким же образом при использовании угловой версии 4 +

getVideoTape() {
    return this.http.get<VideoListModel[]>(`http://ip_adress/api/v1/mixed_galleries/1`);
}
0 голосов
/ 25 мая 2018

Ваши данные JSON недействительны.

это должно быть

{
"data":{
     "date": "2018-02-20 13:10:23",
     "text": "tt",
     "id": 1,
     "items": [
            {
               "date": "2018-02-20 13:10:23",
               "text": "Описание",
               "images": [
                       "image1.jpg",
                       "image2.jpg"
                       ],
               "name": "Изображения",
               "type": "images"
               },
            {
               "date": "2018-02-20 13:10:23",
               "text": "Описание",
               "image": null,
               "type": "video",
               "url": "https://www.youtube.com/embed/v64KOxKVLVg"
               }
            ]
     }
}

, тогда http://json2ts.com/

ваша модель будет

export interface Item {
    date: string;
    text: string;
    images: string[];
    name: string;
    type: string;
    image?: any;
    url: string;
}

export interface Data {
    date: string;
    text: string;
    id: number;
    items: Item[];
}

export interface VideotapeAnswer {
    data: Data;
}
...