将 http 响应映射到 angular 中的接口 7

Mapping http response to interface in angular 7

我有 angular 购物模板,我正在尝试连接用于我的后端的购物车服务,所以我这样做了,但是为了让数据库中的事情更容易,我不得不将请求更改为我的后端从 {quantity, amount, product}{quantity, amount, productId} 所以我不必将整个产品存储在数据库中并且到目前为止它工作正常,现在当我得到响应时我想将它映射到它的界面但是首先,我需要找到具有我在响应中的 ID 的产品,如果我拥有整个产品,我可以映射响应,但同样我不想将产品保存在我的数据库中。这是我的映射代码,但我在调用通过 id:

查找产品的函数时遇到问题
this.getAllProducts().pipe(map(p => p.map((s): CartItem => ({
  currency: s.currency,
  product: this.productService.getProduct(s.product).subscribe(p => p),
  quantity: s.quantity,
  selectedColor: s.selectedColor,
  selectedSize: s.selectedSize,
  userId: s.userId
}))));


  private getAllProducts(): Observable<CartResponse[]> {
    return this.http.get<CartResponse[]>('http://localhost:8082/cart/getAllItems?userId=111').pipe(
      map(o => o.map((sp): CartResponse => ({
        quantity: sp.quantity,
        currency: sp.currency,
        product: sp.product,
        selectedColor: sp.selectedColor,
        selectedSize: sp.selectedSize,
        userId: sp.userId
      }))));
  }


export interface CartResponse {
    product: string;
    quantity: number;
    selectedSize: any;
    selectedColor: string;
    currency: string;
    userId: string;
}

export interface CartItem {
    product: Product;
    quantity: number;
    selectedSize: any;
    selectedColor: string;
    currency: string;
    userId: string;
}

这有点棘手,但您可以使用 switchMap + forkJoin 来完成这项工作。请注意,我使用的是 rxjs@6.5.1。这很重要,因为在以前的版本中 forkJoin 不接收数组作为参数。

import {forkJoin, of as observableOf} from 'rxjs';
import {switchMap, map} from 'rxjs/operators';

....

this.getAllProducts().pipe(
  switchMap((items: CartResponse[]) => {
    // build an array of observables to get all products
    const arrayOfObservables = items.map((item: CartResponse) => 
        this.productService.getProduct(item.product));

    // now go to the database, grab the products, and combine the response
    // with the array of CartResponse you already had
    return forkJoin([
      observableOf(items), 
      ...arrayOfObservables
    ]);
  }),
  map((resultOfForkJoin) => {
    // Notice that resultOfForkJoin is an array
    // - The first item of the array is the original items 
    //    returned by getAllProducts(): CartResponse[]
    // - The rest of the elements of the array are the products

    const items: CartResponse[] = resultOfForkJoin[0];

    // filter the products of resultOfForkJoin and
    // build a JSON of them (for performance), where the attributes 
    // are the products id (I'm suposing each product
    // has a property named after 'id')
    const products = resultOfForkJoin
        .filter((r,index) => index > 0)
        .reduce((acc,a) => {acc[a.id] = a; return acc;}, {});

    // now you can assemble the desired items
    const itemsToReturn = items.map((s: CartResponse): CartItem => ({
      currency: s.currency,
      product: products[s.product],
      quantity: s.quantity,
      selectedColor: s.selectedColor,
      selectedSize: s.selectedSize,
      userId: s.userId
    }));

    return itemsToReturn;
  })
).subscribe((item) => console.log(item));

更新:如果您使用的是以前版本的 rxjs,您可以将 forkJoin 切换为:

forkJoin(observableOf(items), ...arrayOfObservables);

一个stackblitz demo.

您可以使用以下方法,请注意我创建了一些 工厂方法 用假数据来测试它。您可以将它们替换为您的实际实现:

import { of, Observable } from 'rxjs';
import { map, mergeMap, toArray } from 'rxjs/operators';

export interface Product {
  id: string;
  name: string;
}

export interface CartResponse {
  product: string;
  quantity: number;
  selectedSize: any;
  selectedColor: string;
  currency: string;
  userId: string;
}

export interface CartItem {
  product: Product;
  quantity: number;
  selectedSize: any;
  selectedColor: string;
  currency: string;
  userId: string;
}

const fakeGetAllProducts = (): Observable<CartResponse[]> => of<CartResponse[]>([
  { currency: "US", product: "PX1", quantity: 10, selectedColor: "red", selectedSize: "L", userId: "UX1" },
  { currency: "EU", product: "PX50", quantity: 10, selectedColor: "blue", selectedSize: "S", userId: "UX2" }
]);
const fakeGetProduct = (id: string): Observable<Product> => of<Product>({ id, name: `Product ${id}` });

// Here the cart response is destructured into 2 values: the product id and everything else
const mapResponseToItem = ({ product, ...noProduct }: CartResponse): Observable<CartItem> => fakeGetProduct(product).pipe(
  map<Product, CartItem>(product => ({ ...noProduct, product }))
);

fakeGetAllProducts().pipe(
  // flatten the array in order to process single items from it sequentially
  mergeMap(items => items),
  // map a cart response into a cart item observable and flatten it
  mergeMap(mapResponseToItem),
  // collect the sequentially processed elements into an array
  toArray()
).subscribe(console.log);

您可以看到代码在 this blitz

中运行