【问题标题】:Angular using RxJS - How to map data when JSON object has multiple propertiesAngular 使用 RxJS - 当 JSON 对象具有多个属性时如何映射数据
【发布时间】:2020-11-05 14:32:58
【问题描述】:

我的代码最初可以正常工作,直到我需要更改 JSON 对象的结构。这是我最初的 JSON 对象结构,它只是我的 API 返回的产品的简单列表。为了简洁起见,我缩写:

[{"PicFile":"11382","ShortDesc":"At Home Slot Machine","ActualPrice":12.99, .... }]

在我的产品服务中,我调用我的 API 并返回一个转换为我的产品模型的列表:

getProductsByCategory(categoryCode: string): Observable<Product[]> {
let url = this.baseAPIUrl + .....
return this.httpClient.get(url)
       .pipe(
         map((data: any[]) => data.map((item) => this.adapter.convert(item)))
     );
}

这是我的适配器代码。我创建了一个可以接受任何类型对象的通用适配器,这就是它的实现:

import { Injectable } from "@angular/core";
import { Adapter } from "./adapter";

export class Product {
    constructor(
        public PicFile: string,
        public ShortDesc: string,
        public ActualPrice: number,
        .... other properties here

    ) { }
}

@Injectable({
    providedIn: "root",
})
export class ProductAdapter implements Adapter<Product> {
    convert(item: any): Product {   
        return new Product(item.PicFile, item.ShortDesc, item.ActualPrice, .... );
    }
}

在我的产品组件中,我订阅了从服务返回的 observable:

 loadAllProductsByCategory(categoryCode: string) {
        this.loadingSubject.next(true);

        this.productService.getProductsByCategory(categoryCode).pipe(
            catchError(() => of([])),
            finalize(() => this.loadingSubject.next(false))
        )
            .subscribe(products => this.productsSubject.next(products));
    }

这与我的简单 JSON 结构完美配合。我需要为分页目的添加一个计数属性,并且很可能在未来添加其他属性。新的 JSON 对象具有保存产品列表的“Data”属性和称为“Count”的属性。

{"Data":[{"PicFile":"11382","ShortDesc":"At Home Slot Machine","ActualPrice":12.99, ...}], "Count":41}

那么,我的问题是如何更改我的服务代码以查找“数据”属性并进行转换?:

return this.httpClient.get(url)
       .pipe(
         map((data: any[]) => data.map((item) => this.adapter.convert(item))) <-- how to look for "Data" property and convert only that list, not the whole object?
     );

我已经尝试了几件事,包括在此处订阅,但随后它被转换为订阅,我需要返回可观察对象。我确信它可以完成,但我对 Angular 和 RxJS 还很陌生。我似乎无法正确理解映射语法。

提前感谢您提供的任何帮助, 吉姆

【问题讨论】:

  • 我不明白为什么你有一个适配器,而你可以订阅 API 并期待一个产品。
  • 试试map((data: any) =&gt; data['Data'].map((item) =&gt; this.adapter.convert(item)))

标签: json angular rxjs


【解决方案1】:

如果您返回的数据结构发生了变化,您需要在服务中更新您的map

 return this.httpClient.get(url).pipe(
    map( (data: any) => data.Data.map((item) => this.adapter.convert(item)) )
);

您可能应该更改您传递到地图中的属性名称以避免混淆。即

(resp: any) => resp.Data.map((item) => this.adapter.convert(item))

从服务返回的数据的结构已从 Array 更改为 Object。因此,您必须更改映射过程

此更新后的代码只会从您的响应中返回 Data 数组。

如果您还需要返回计数,则需要更新您的服务方法getProductsByCategory 以返回一个包含计数和数据的对象。

【讨论】:

  • 非常感谢您快速准确的回复。我确实听取了您的建议并更改了“数据”属性名称。它现在运行良好。您提出了一个很好的观点,即我需要访问 count 属性,可能还有其他我将添加的属性。您能否就我需要做什么提供一些见解?
【解决方案2】:

您可以尝试以下方式:

return this.httpClient.get(url).pipe(
  map((response: any) => {
    response.data=response.data.map((item) => this.adapter.convert(item));
    return response;
  })
);

【讨论】:

    【解决方案3】:

    从服务获取 JSON 时的常见映射模式是使用响应中的数据创建或丰富对象

     return this.httpClient.get(url).pipe(
        map(response => ({
          ProcessingTimeStamp: Date.now(),
          fullName: `${response.productName} (${response.productShortHand})`,
          count: response.count,
          data: response.Data.map(item => this.adapter.convert(item)),
          foo: response.bar,
          message: `I can sell you ${count}, of ${response.productShortHand} for cheap! Buy from me!`
        }))
    );
    

    此模式将响应转换为您以后可以随意使用的对象。这里将响应转换为具有以下形式的对象:

    {
      ProcessingTimeStamp: number,
      fullName: string,
      count: number,
      data: item[],
      foo: any,
      message: string
    }
    

    你的能力真的不受限制。如果它适用于 TS/JS,你可以做到。您可以推送函数或嵌套的 observables,等等。

    【讨论】:

    • 感谢您的帖子和解释。我在尝试实现您的代码时遇到了一些语法错误。我得到“类型对象上不存在属性'计数'”,“数据”也是如此。这是我正在尝试的代码:``` getProductsByCategoryNEW(categoryCode: string): Observable { ...您的代码在这里...我是否指定了我的返回类型不正确? @Mrk Sef
    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多