I'm using WooCommerce v3 api, my goal is to show a list with all the categories and horizontally show all the products by category, like:
Category name:
product product1 product2
Category 2 name:
product product1 product2
but there is not endpoint to get all this, so I get all the categories first with
getAllCats(): Observable<any>{
const req = this.httpS.get(`${API.prod.url API.prod.woo 'products/categories/?consumer_key=' API.prod.consumer_key '&consumer_secret=' API.prod.consumer_secret}`);
return req;
}
getProductsByCat(catId: number): Observable<any>{
const req = this.httpS.get(`${API.prod.url API.prod.woo 'products?consumer_key=' API.prod.consumer_key '&consumer_secret=' API.prod.consumer_secret '&category=' catId}`);
return req;
}
and then on my component I am doing this
categories: any = {};
cats: Array<any> = [];
products: Array<any> = [];
catsWithAllProducts: any = {
category: [{
products: []
}]
};
kats: Category[] = [];
showAllCatsWithProducts(){
this.pService.getAllCats().subscribe((cats) => {
for (const [i,cat] of cats.entries()) {
this.pService.getProductsByCat(cat.id).subscribe((products) => {
this.cats.push(cat);
this.products.push(products);
this.catsWithAllProducts.category = cat;
this.kats.push(this.catsWithAllProducts); //new categories array with products
});
}
});
}
I have two problems, the products[] is empty, I'm confused with, how to achieve to create a new object or array or array of objects with all the products inside a category. Right what is printed on screen is all the categories but with repeated name I have 10 categories, and it shows the first name that receives * the number of categories. What I've been thinking is that first it should be async, I mean is an observable but it is pushing to the array each element with or without response yet. I'm kind of stuck here, thanks for reading me.
CodePudding user response:
I'm not really sure, but try if this changes over your code solve your possible async problem:
getAllCats(): Observable<any>{
return this.httpS.get(`${API.prod.url API.prod.woo 'products/categories/?consumer_key=' API.prod.consumer_key '&consumer_secret=' API.prod.consumer_secret}`);
}
getProductsByCat(catId: number): Observable<any>{
return this.httpS.get(`${API.prod.url API.prod.woo 'products?consumer_key=' API.prod.consumer_key '&consumer_secret=' API.prod.consumer_secret '&category=' catId}`);
}
showAllCatsWithProducts() {
this.pService.getAllCats()
.pipe(
switchMap( cat => this.pService.getProductsByCat(cat.id) ),
)
.subscribe( products => {
this.cats.push(cat);
this.products.push(products);
this.catsWithAllProducts.category = cat;
this.kats.push(this.catsWithAllProducts);
});
)
CodePudding user response:
I'd recommend first changing your service to define what you need as observables, hiding as much complexity from the components as possible, like this:
export interface Category {
id: number;
}
export interface Product {
id: number;
}
@Injectible()
export class pService {
readonly categories$: Observable<Category[]> = this.httpS.get(`${API.prod.url API.prod.woo 'products/categories/?consumer_key=' API.prod.consumer_key '&consumer_secret=' API.prod.consumer_secret}`).pipe(
take(1),
shareReplay()
);
readonly productsPerCategory$: Observable<[Category, Product[]]> = this.categories$.pipe(
mergeMap(category => this.getProductsByCat(category.id).pipe(
map(products => [category, products])
)),
shareReplay()
);
readonly allProducts$: Observable<Product[]> = this.productsPerCategory$.pipe(
mergeMap(ppc => from(ppc[1])),
distinct((p: Product) => p.id), // if products overlap, otherwise remove this line if every product is in only one category.
shareReplay()
);
readonly allProducts: Promise<Product []> = this.allProducts$.pipe(toArray()).toPromise;
private getProductsByCat(catId: number): Observable<Product[]>{
return this.httpS.get(`${API.prod.url API.prod.woo 'products?consumer_key=' API.prod.consumer_key '&consumer_secret=' API.prod.consumer_secret '&category=' catId}`);
}
}
This is all without a subscribe. You might be able to get away without a single subscribe in your comment, too, if you use the async pipe, depending on what you need.
CodePudding user response:
I handle it with async/await and changing the regular for
to forEach
at showAllCatsWithProducts()
method
async showAllCatsWithProducts(){
this.pService.getAllCats().subscribe((cats) => {
cats.forEach(async cat => { //for each category
const response = await this.pService.getProductsByCat(cat.id).subscribe(res => { //It's gonna wait por their products
this.categories.push({id: cat.id,name: cat.name,slug:cat.slug, products: res}); //Push category with products
});
});
});
}