我有两种方法可以对 Rest API 进行 HTTP 调用。一个是 getProducts(),它将返回一个产品数组,另一个是 getProductsDetail(),它可以将该数组作为参数,并返回填充了附加字段的产品数组。
我想依次调用这两个 API,getProductsDetail() 取决于 getProducts() 的结果,但我希望我的 Observable 一旦准备好就从 getProducts() 发出结果。然后让 getProductsDetail() 在此调用返回时发出额外的详细信息。
有没有办法使用像 concatMap 或 mergeMap 这样的 RxJS 运算符来做到这一点?我想让我的模板尽快开始显示,但在可用时填写额外数据
更新:
您好,感谢您的回复!对不起,我目前只有伪代码,但我认为我最初的尝试将类似于 Authur 下面的内容
initProductsPage(): Observable<Products[]>{
this.productsService.getProducts().pipe(
switchMap(
(products: Products[]) => {
// would like to also emit products here
return this.productsService.getProductsDetail(products);
}
)
}
我的理解是,在这种情况下,initProductsPage() 的订阅者只会在 getProductsDetail() 返回时收到输出。我想让该订阅者在执行 getProductsDetails() 时获得产品。
回答1
假设 getProducts()
和 getProductsDetail()
返回一个 Observable<Product[]>
,你可以这样做:
getProductsWithDetailsHydration(): Observable<Product[]> {
const productsShared$ = this.getProducts().pipe(share()); // <- to share same GET products request.
return merge(
productsShared$, // <- 1st obs Gets and emits Products
productsShared$.pipe( //<- 2nd obs Gets details using products response and emit Products with Details
concatMap((products) => this.getProductsDetail(products))
)
);
}
干杯
回答2
另一种来自 API 端的方法是使用 getProductDetail$() 方法。其中可以获取单个产品的详细信息。然后您可以轻松地在模板本身中使用 async
并填充模板。
示例模板代码
<ng-container *ngIf="getProduct$() | async as product">
// Some info on product
<div>{{product.title}}</div>
<ng-container *ngIf="getProductDetail$(product.id) | async as productDetail">
// Some info on product details
<div>{{productDetail.description}}</div>
</ng-container>
</ng-container>
回答3
我认为解决这个问题的更好方法是将两个可观察对象分开。
然后您可以订阅并获得 values:
// Class variables
products: Products[];
products$: Observable<Products[]>;
productsDetails: ProductsDetails[];
productsDetails$: Observable<ProductsDetails[]>;
// Call OnInit or OnChanges depending of your needs
initProductsPage(): void {
// Initialize the observables
this.products$ = this.productsService.getProducts();
this.productsDetails$ = this.products$.pipe(
switchMap((products) => this.getProductsDetail(products))
);
// Using take(1) to complete the observable after it gets the value
this.products$.pipe(take(1)).subscribe(products => {
this.products = products;
});
// Using take(1) to complete the observable after it gets the value
this.productsDetails$.pipe(take(1)).subscribe(productsDetails => {
this.productsDetails = productsDetails;
});
}
然后你可以在你的模板中使用 products
和 productsDetails
。
您也可以使用 |async
直接在模板上使用 observables,在这种情况下 initProductsPage()
的第二部分将不是必需的。
// Class variables
products: Products[];
products$: Observable<Products[]>;
productsDetails: ProductsDetails[];
productsDetails$: Observable<ProductsDetails[]>;
// Call OnInit or OnChanges depending of your needs
initProductsPage(): void {
// Initialize the observables
this.products$ = this.productsService.getProducts();
this.productsDetails$ = this.products$.pipe(
switchMap((products) => this.getProductsDetail(products))
);
}