HttpClient, как преобразовать вложенный JSON и сопоставить с моделью домена - PullRequest
0 голосов
/ 29 сентября 2018

Привет, я довольно новичок в программировании, и я искал ответ в Интернете в течение нескольких дней для решения своей проблемы, не находя ничего, что мне помогло бы, независимо от того, что я делал.Я получаю гнездо JSON в качестве ответа.Объект json, между прочим, имеет динамический ключ.Я хочу преобразовать объект json в мою модель, чтобы я мог легко получить доступ к данным в моем шаблоне.Цени любую помощь

вот пример данных json Ответ Amadeus API

Вот мой сервис

getResults(params: any) {
  this.getItiniraries(params).subscribe((res) => {
    this.itinirary = res;
    // console.log(res);
    this.updatedResults.next(this.itinirary);
  });
}


getItiniraries(params: any): Observable<Itinirary> {
  return this.http.get<Itinerary>('http://localhost:4202/api/itinirary' ,  {params: params})
  ; }

модели

Маршрутная модель

import { Result } from './result.model';
import { Meta } from '@angular/platform-browser';

// Model for data from Amadeus flight affiliate search

 export class Itinirary {

 public meta: Meta;
 public results: Result[];
 constructor(res: any) {
  this.meta = res.meta;
  this.results = res.results;

}}

Результат Модель

   import { Flight } from './flight.model';
    import { Fare } from './fare.model';


   export class Result {
   public outbound_duration: string;
   public outbound_flights: Flight[];
   public inbound_duration: string;
   public inbound_flights: Flight[];
   public fare: Fare;
   public cabin_code: string;
   public fare_family: string;
   public travel_class: string;
   public merchant: string;
   public airline: string;
   public deep_link: string;
   constructor(result: any) {
   this.outbound_duration = result.outbound.duration;
   this.outbound_flights = result.outbound.flights;
   this.inbound_duration = result.inbound.duration;
   this.inbound_flights = result.inbound.duration;
   this.fare = result.fare;
   this.cabin_code = result.cabin_code;
   this.fare_family = result.fare_family;
   this.travel_class = result.travel_class;
   this.merchant = result.merchant;
   this.airline = result.airline;
   this.deep_link = result.deep_link;
   }
   }

Модель полета

import { BookingInfo } from './bookingInfo.model';


export class Flight {
public departs_at: Date;
public arrives_at: Date;
public marketing_airline: string;
public operating_airline: string;
public flight_number: number;
public aircraft: number;
public booking_info: BookingInfo;
public origin_airport: string;
public origin_terminal: string;
public destination_airport: string;
public destination_terminal: string;
constructor(flight: any) {
this.departs_at = flight.departs_at;
this.arrives_at = flight.arrives_at;
this.marketing_airline = flight.marketing_airline;
this.operating_airline = flight.operating_airline;
this.flight_number = flight.flight_number;
this.aircraft = flight.aircraft;
this.booking_info = flight.booking_info;
this.origin_airport = flight.origin_airport;
this.origin_terminal = flight.origin_terminal;
this.destination_airport = flight.destination_airport;
this.destination_terminal = flight.destination_terminal;

}}

метамодель

    import { Carrier } from './carrier.model';

export class Meta {
public carriers: {[key: string]: Carrier };
constructor(meta: any) {
this.carriers = meta.carriers;
}
}

модель авианосца

export class Carrier {
public identifier: string;
public name: string;
public logoSmall: string;
public logoMedium: string;
constructor(carrier: any) {
this.identifier = carrier;
this.name = carrier.name;
this.logoSmall = carrier.logos.samll;
this.logoMedium = carrier.logos.medium;
}
}

в моей модели полета, я также хотел бы добавить два свойства даты и времени, которые являются производными отоставки_посещения и прибытия_прибытия.

По сути, я хочу иметь возможность передать весь Intinirary объект на мой взгляд, чтобы я мог через строку iterpolation получить значения.

ex после использования ngFor или let result из itinirary.results

{{result.outbound_flights [0] .departure_date}} и т. Д.

будет очень признателен за хорошее руководство

обновленная служба

  getItiniraries(params: any): Observable<any> {
  return this.http.get<any>('http://localhost:4202/api/itinirary' ,  
  {params: params})
  .pipe(map((AmdResponse) => {
    const parsedRes = JSON.parse(AmdResponse);
    const itin = new Itinirary(parsedRes);
    return itin;
  } )); }

Обновленная мета-модель и модель носителя Meta

import { Carrier } from './carrier.model';

export class Meta {
public carriers: {[key: string]: Carrier };
constructor(meta) {
this.carriers = {};
Object.keys(meta.carriers).forEach(code => {
this.carriers[code] = new Carrier(meta.carriers[code]);
});
}
}

модель носителя

export class Carrier {
public name: string;
public logoSmall: string;
public logoMedium: string;
constructor(cObject ) {
Object.keys(cObject).forEach(code => {
  this.name = cObject.name;
});
Object.keys(cObject.logo).forEach(code => {
this.logoSmall = cObject.logos.samll;
this.logoMedium = cObject.logos.medium;
});
}
}

Я также обновил свою модель результата, как эта,Имеет ли это смысл?

import { Flight } from './flight.model';
import { Fare } from './fare.model';


export class Result {
public outbound_duration: string;
public outbound_flights: Flight[];
public inbound_duration: string;
public inbound_flights: Flight[];
public fare: Fare;
public cabin_code: string;
public fare_family: string;
public travel_class: string;
public merchant: string;
public airline: string;
public deep_link: string;
constructor(result) {
this.outbound_duration = result.outbound.duration;
// this.outbound_flights = this.loop(this.outbound_flights, 
 result.outbound.flights);
this.inbound_duration = result.inbound.duration;
// this.inbound_flights = this.loop(this.inbound_flights, 
result.inbound.flights);
this.fare = new Fare(result.fare);
this.cabin_code = result.cabin_code;
this.fare_family = result.fare_family;
this.travel_class = result.travel_class;
this.merchant = result.merchant;
this.airline = result.airline;
this.deep_link = result.deep_link;

  for (let i = 0; i < result.outbound.flights.length; i++) {
    this.outbound_flights[i] = new Flight(result.outbound.flights[i]);
  }
  for (let i = 0; i < result.inbound.flights.length; i++) {
    this.inbound_flights[i] = new Flight(result.inbound.flights[i]);
  }


  }
  // loop(a, b) {
  //   for (let i = 0; i < b.length; i++) {
  //     a[i] = new Flight(b[i]);
  //   }
  //   return a;
  // }
  }

Я тестировал оба с помощью функции или отдельного цикла.

Я также добавил dateFormatterService в свою модель полета, хотя не был уверен, куда его импортировать, поскольку я не смог импортировать его в конструктор.

import { BookingInfo } from './bookingInfo.model';
import { DateFormatterService } from '../../Shared/dateFormatter.service';


export class Flight {
private df: DateFormatterService; // can i have it here instead of constructor?
public departs_date: string;
public departs_time: string;
public arrives_date: string;
public arrives_time: string;
public marketing_airline: string;
public operating_airline: string;
public flight_number: number;
public aircraft: number;
public booking_info: BookingInfo;
public origin_airport: string;
public origin_terminal: string;
public destination_airport: string;
public destination_terminal: string;
constructor(flight: any ) { 
const depart_at = new Date(flight.departs_at);
const arrive_at = new Date(flight.arrives_at);

this.departs_date =  this.df.transformDate(depart_at);
this.departs_time = this.df.transformTime(depart_at);
this.arrives_date = this.df.transformDate(arrive_at);
this.arrives_time = this.df.transformTime(arrive_at);
this.marketing_airline = flight.marketing_airline;
this.operating_airline = flight.operating_airline;
this.flight_number = flight.flight_number;
this.aircraft = flight.aircraft;
this.booking_info = new BookingInfo(flight.booking_info);
this.origin_airport = flight.origin_airport;
this.origin_terminal = flight.origin_terminal;
this.destination_airport = flight.destination_airport;
this.destination_terminal = flight.destination_terminal;
}}

Ответы [ 3 ]

0 голосов
/ 29 сентября 2018

В качестве преамбулы следует понимать, что нет способа получить строку JSON (из API или другого источника) и сделать ее экземпляром определенного пользовательского класса.

Я думаю, вы начали с правильной идеи в своем мета-конструкторе ... что вам нужно проанализировать полученные данные в ваших собственных объектах.Вам просто нужно пойти дальше, явно разбирая все свойства полученного JSON в новые объекты (ваших классов) по одному, пока вы не закончите.Возможно, это утомительно, но необходимо, если вы хотите, чтобы ваша собственная иерархия классов представляла полученные данные (которые, возможно, НЕ нужны, но это не мое решение).

Я предполагаю, что вы уже получили буквальный объект JS из данных, полученных из ответа API, что-то вроде этого:

const itins = JSON.parse( amadeusResponse );

Затем вы позволяете своим классам выполнять работу:

const meta = new Meta( itins.meta );
//or
const alternate = new Meta();
alternate.fromJSON( itins.meta );

Выше видно, что вы можете иметь метод, который читает данные JSON, или конструктор.Выбор будет сделан в зависимости от того, ожидаете ли вы когда-либо создать объект Meta, не имея сначала JSON (в этом случае альтернатива метода, вероятно, лучше).

В любом случае реализация читает объект JS, который выдать его, и анализирует полученную структуру данных в структуру, которую вы хотите иметь в ваших экземплярах локального класса.Например, в конструкторе Meta ...

constructor( meta ) {
    this.carriers = {};
    // which carriers did we get?
    Object.keys(meta.carriers).forEach( code =>
        this.carriers[code] = new Carrier( code, meta.carriers[code] )
    );

В свою очередь, конструктор класса Carrier будет считывать свойства "logos" и "name" либо в свои поля, которые могут включать в себя еще больше экземпляров класса.

Продолжайте, пока не закончите.

0 голосов
/ 30 сентября 2018

с использованием новых функций es6 это довольно просто this._results = value.map(x => new Result(x)); может быть this._results = [...value] в этом случае, если значение является вложенным массивом json, оно будет плоским, как вы хотите.

0 голосов
/ 29 сентября 2018

Если вы хотите создать дерево экземпляров моделей Javascript из JSON, вы можете сопоставить JSON с конструктором корневого класса следующим образом:

getItiniraries(params: any): Observable<Itinerary> {
   return this.http.get<Itinerary>('http://localhost:4202/api/itinirary',  {params: params}).pipe(map(x => new Itinerary(x)); 
}

Затем определите следующий конструктор для всей вашей моделиклассы:

constructor(obj) {
   Object.assign(this, obj);
}

Затем для всех детей модельного класса замените эти объявления public meta: Meta; на:

private _meta: Meta;

get meta() {
   return this._meta;
}

set meta(value: any) {
   this._meta = new Meta(value);
}

То же самое относится и к детям, как Array:

private _results: Result[];

get results() {
   return this._results;
}

set results(value: any) {
   this._results = value.map(x => new Result(x));
}

Тогда ваше дерево объектов будет состоять из экземпляров классов вашей модели, и вы сможете использовать потенциальные функции, которые вы определите (например, функции форматирования данных или что-то еще)

...