将HTTP响应映射到角度为7的界面

时间:2019-07-12 22:46:22

标签: angular http rxjs angular-httpclient

我有一个有角度的购物模板,我正在尝试连接用于后端的购物车服务,因此我这样做了,但是为了简化数据库,我不得不将请求从{{1 }}到{quantity, amount, product},因此到目前为止,我不必将整个产品存储在数据库中,并且它的工作情况还不错,现在,当我收到响应时,我想将其映射到其接口,但是首先我需要找到产品具有我在响应中具有的ID,如果我拥有整个产品,则可以映射响应,但是我又不想将产品保存在数据库中。这是我的映射代码,但是有一个问题,我在调用函数时要按ID查找产品:

{quantity, amount, productId}

2 个答案:

答案 0 :(得分:2)

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

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中起作用

答案 1 :(得分:1)

这有点棘手,但是您可以使用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