HttpClient如何将嵌套的json转换并映射到模型域

时间:2018-09-29 19:44:07

标签: json angular observable httpclient amadeus

嗨,我是编程的新手,几天来我一直在网上寻找问题的答案,而无论我做什么,都找不到对我有用的东西。我正在接收nest json作为响应。 json对象除其他外似乎具有动态密钥。我想要的是将json对象转换为我的模型,以便可以轻松访问模板中的数据。感谢任何帮助

这是json数据的示例 Amadeus API response

这是我的服务

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

在我的飞行模型中,我还想添加两个属性,即日期和时间,这些属性是从deriving_at和arrival_at派生的。

基本上,我希望能够将整个Intinirary对象传递给我的视图,以便我可以通过字符串迭代获得值。

使用ngFor后的

ex或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;
  } )); }

更新的元模型和运营商模型 元

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 :(得分:0)

如果要从JSON创建模型的Javascript实例树,可以将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));
}

然后,您的对象树将由模型类的实例组成,您将能够从将要定义的潜在功能(例如数据格式化功能或其他任何功能)中受益

答案 1 :(得分:0)

作为序言,请理解没有办法(从API或其他地方)接收JSON字符串并使之成为特定自定义类的实例。

我认为您从Meta构造函数中的正确想法开始...。您需要将接收到的数据解析为自己的对象。您只需要走得更远,就可以一次将一个接收的JSON的所有属性显式地解析为一个新的对象(您的类),直到完成为止。如果您希望自己的类层次结构表示接收到的数据(可能不需要,但这不是我要决定的),则可能很乏味,但这是必需的。

我假设您已经从API响应接收的数据中获得了一个JS文字对象,如下所示:

const itins = JSON.parse( amadeusResponse );

然后,让您的班级完成这项工作:

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

通过以上内容,您可以看到可以使用读取JSON数据的方法或构造函数。将根据您是否希望在不首先拥有JSON的情况下创建Meta对象来进行选择(在这种情况下,使用Alternate方法可能会更好)。

在任何一种情况下,实现都会读取您提供的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类构造函数将在其字段中读取“徽标”和“名称”属性,其中可能包括更多的类实例。

继续前进,直到完成。

答案 2 :(得分:0)

使用新的es6功能,this._results = value.map(x => new Result(x));很容易this._results = [...value],在这种情况下,如果值是嵌套的json数组,则它会随心所欲。