Home > OS >  how to manage data from request inside request loop
how to manage data from request inside request loop

Time:11-29

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
        });
      });
    });
  }
  • Related