skip to Main Content

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:

enter image description here

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.

3

Answers


  1. Chosen as BEST ANSWER

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

  2. 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);
         });
    )
    
    Login or Signup to reply.
  3. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search