将 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);
您可以使用以下方法,请注意我创建了一些 工厂方法 用假数据来测试它。您可以将它们替换为您的实际实现:
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
中运行
我有 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);
您可以使用以下方法,请注意我创建了一些 工厂方法 用假数据来测试它。您可以将它们替换为您的实际实现:
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
中运行