Как отобразить http ответ на тип модели клиента в Angular - PullRequest
1 голос
/ 29 сентября 2019

У меня есть модель MyObejct, как это в клиенте:

class MyObject{
 id: number;
 name: string;
 active: boolean;
}

И данные http-ответа json, такие как:

[
 {
  id: "1",
  name: "object1",
  active: "true",
 }
]

Ответ http - это пара ключ-значение, и всетип значения - строка.Итак, как мне сопоставить http-ответ с типом «MyObject».Функция http get выглядит следующим образом:

getMyObejct(name: string): Observable<MyObject> {
 const url = this.url + 'name/' + name;
 return this.http.get<MyObject>(url);  // This is part I'm confused
}

getAllObjects(): Observable<MyObject[]> {
 return this.http.get<MyObject>(this.url); // How to map this reponse to MyObject
}

Все значения ответов http имеют строковый тип, но MyObject имеет число типов и логическое значение.Как я могу это сделать?

Ответы [ 4 ]

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

Чтобы указать тип объекта ответа, сначала определите интерфейс с необходимыми свойствами .(Используйте интерфейс, а не класс; ответ не может быть автоматически преобразован в экземпляр класса.)

interface MyObject{
 id: number;
 name: string;
 active: boolean;
}

getAllObjects(): Observable<MyObject[]> {
 return this.http.get<MyObject>(this.url); // now returns an Observable of MyObject[]
}

Подробнее об этом здесь - https://angular.io/guide/http#typechecking-the-response

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

Возможно, вы захотите взглянуть на класс-трансформер .Метод plainToClass преобразует простой объект javascript в экземпляр определенного класса.

import {plainToClass} from "class-transformer";

fetch(url).then((objects: MyObject[]) => {
    const realMyObjects = plainToClass(MyObject, objects);
    // now each object in realMyObjects is an instance of MyObject class
});

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

class MyPayload {
  prop: string
}

const result1 = plainToClass(MyPayload, { prop: 1234 }, { enableImplicitConversion: true });

/**
 *  result1 will be `{ prop: "1234" }` - notice how the prop value has been 
 *  converted to string.
 */

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

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

getAllObjects(): Observable<MyObject[]> {
   return this.http.get(this.url).pipe(
      map((data: any[]) => data.map((item: any) => {
          const model = new MyObject();
          Object.assign(model, item);
          return model;
       }))
       );
}

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

export class ModelMapper<T> {
  _propertyMapping: any;
  _target: any;
     constructor(type: { new(): T ;}){
        this._target = new type();
        this._propertyMapping = this._target.constructor._propertyMap;
     }

     map(source){
       Object.keys(this._target).forEach((key) => {
         const mappedKey = this._propertyMapping[key]
         if(mappedKey){
           this._target[key] = source[mappedKey];
         }
         else {
           this._target[key] = source[key];
         }
       });
       Object.keys(source).forEach((key)=>{
         const targetKeys = Object.keys(this._target);
         if(targetKeys.indexOf(key) === -1){
           this._target[key] = source[key];
         }
       });
      return this._target;
     }
}

Теперь импортируйте этот класс в service.ts и используйте его для преобразования ответа json.

import { ModelMapper } from './modelMapper';

public get<T>(url: string, itemType: any): Observable<T> {
    if (!url) {
      return;
    }

    return this.http.get<T>(url)
      .pipe(
        map(data => data.map((item: any) => {
          return new ModelMapper(itemType).map(item);
        }
      ))
    );
  }
}

Если вы хотите выполнить переименование поля данных бэкенда, вы можете создать декоратор PropertyMap, как показано ниже

export function propertyMap(sourceProperty : string) {
    return function (target: any, propertyKey : string) {
      if(!target.constructor._propertyMap) { 
        target.constructor._propertyMap = {};
      } 
      target.constructor._propertyMap[propertyKey] = sourceProperty;
    }
}

Затем вы используете его в классе вашей модели

@propertyMap('namealias')
public name: string;
0 голосов
/ 29 сентября 2019

Это зависит от того, нужен ли вам экземпляр MyObject или просто что-то с такими же свойствами.

Если вам просто нужен объект с такими же свойствами, вы можете сделать:

return this.http.get<MyObject>(url).map( (obj) => {
  id: Number(obj.id), 
  name: obj.name,
  active: obj.active === 'true'
});

Если вам нужен фактический экземпляр MyObject (например, если у MyObject есть методы), вы можете сделать:

return this.http.get<MyObject>(url).map( (obj) => Object.assign(new MyObject(), {
  id: Number(obj.id), 
  name: obj.name,
  active: obj.active === 'true'
}));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...