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