Search code examples
angularrxjsangular-akita

Observable Async Pipe Not Returning Values


EDIT: DEMO OF THE NON-WORKING CODE

I'm having issues with using the async pipe on an observable. It works in one app but not the other.

The working one can be found here: https://stackblitz.com/edit/angular-ry1dev

The non-working code:

products.component.ts:

export class ProductsComponent implements OnInit {
  products$: Observable<Product[]>;

  //NOTE: this service is coming from Akita state management
  constructor( private productService: ProductService ) {}

  ngOnInit() {
    this.products$ = this.productService.getProducts();
  }
}

products.service.ts (Akita state management):

@Injectable({ providedIn: 'root' })
export class ProductService {
  constructor( private prodStore: ProductStore, private prodService: ProductsService ) {}

  getProducts() {
    return this.prodService.getProducts().pipe(
      tap( result => {
        let dataArr = [];
        for (let obj in result) {
          dataArr.push(result[obj]);
        }

        this.prodStore.add(dataArr)
      })
    )
  }
}

products.service.ts (http called by prodService above):

getProducts() {
  return this.http.get<Product[]>(`${this.API}/products`);
}

products.component.html:

<mat-accordion *ngIf="products$" class='product-accordion'>
  <mat-expansion-panel *ngFor="let product of products$ | async">
    <mat-expansion-panel-header>
      SKU: {{ product.sku }}
    </mat-expansion-panel-header>

    <p>${{ product.price }}</p>
    <p>{{ product.description }}</p>

  </mat-expansion-panel>
</mat-accordion>

The above app's store and query components are the same as the stackblitz.

I should be getting a list of products like the list of todos in the stackblitz but it's erroring in the HTML with:

ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

Why is it working on stackblitz but not in my app?

EDIT: DEMO OF THE NON-WORKING CODE


Solution

  • Could you check what's the actual response from your back-end? Your front-end's assumption is to fetch an array but seems like your back-end is responding with something like this:

    {
      "something": {},
      "something": {}
    }
    

    the response should be an array instead, like this:

    [
      "something": {},
      "something": {}
    ]
    

    EDIT: If we can not change the backend behavior. Then we need to update our getProducts method to return what our async products binding requires.

    getProducts() {
        return this.prodService.getProducts().pipe(
          map( result => {
            let dataArr = [];
            for (let obj in result) {
              dataArr.push(result[obj]);
            }
    
            this.prodStore.add(dataArr);
            return dataArr;
          })
        )
      }