Что вызывает ошибку «разрешены только массивы и итерации» в этом приложении Angular 13?

Я работаю над приложением для электронной коммерции, интерфейс которого сделан на Angular 13.

Я пытаюсь получить продукты из API и отобразить их в виде карточек.

Для этого в app\app.module.ts у меня есть:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { Routes, RouterModule } from '@angular/router';
import { NavbarComponent } from './components/navbar/navbar.component';
import { FooterComponent } from './components/footer/footer.component';
import { SidebarComponent } from './components/sidebar/sidebar.component';
import { HomeComponent } from './components/home/home.component';
import { ProductsListComponent } from './components/products-list/products-list.component';
import { ProductItemComponent } from './components/product-item/product-item.component';

const routes: Routes = [
  { path: '', component:  HomeComponent},
  { path: 'products', component:  ProductsListComponent},
];

@NgModule({
  declarations: [
    AppComponent,
    NavbarComponent,
    FooterComponent,
    SidebarComponent,
    ProductsListComponent,
    ProductItemComponent 
  ],
  imports: [
    CommonModule,
    BrowserModule,
    HttpClientModule,
    RouterModule.forRoot(routes),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

В app/services/product.service.ts:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { Product } from '../models/product';

@Injectable({
  providedIn: 'root'
})
export class ProductService {

  products: Product[] = [];

  apiURL: string = 'https://dummyjson.com';

  constructor(private http: HttpClient) {}

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

В компоненте список продуктов у меня есть`:

// Typescript:

import { Component, OnInit } from '@angular/core';
import { Product } from '../../models/product';
import { ProductService } from '../../services/product.service';

@Component({
  selector: 'app-products-list',
  templateUrl: './products-list.component.html',
  styleUrls: ['./products-list.component.css']
})
export class ProductsListComponent implements OnInit {

  products: Product[] = [];

  constructor(private ProductService: ProductService) { }

  ngOnInit(): void {
   this.ProductService.getProducts().subscribe((products) => (this.products = products));
  }

}

Шаблон:

<!-- Card list Begin -->
<ng-container *ngIf = "products">
<div class = "row">
    <div *ngFor = "let product of products" class = "col-sm-6 col-md-4 col-xl-3">
        <app-product-item></app-product-item>
    </div>
</div>
</ng-container><!-- Card list End -->

В компоненте элемент продукта:

// Typescrypt

import { Component, OnInit, InputDecorator, Input } from '@angular/core';
import { Product } from '../../models/product';

@Component({
  selector: 'app-product-item',
  templateUrl: './product-item.component.html',
  styleUrls: ['./product-item.component.css']
})
export class ProductItemComponent implements OnInit {

  @Input()
  product!: Product;

  constructor() { }

  ngOnInit(): void {
  }

}

Шаблон:

<div class = "card text-center p-0">
    <div class = "card-header p-1">
            {{ product.title }}
    </div>
    <div class = "card-body px-1 py-0">
            <img src = "product.thumbnail" alt = "Product" class = "img-fluid">

            <p class = "price text-muted m-0 pb-1 pt-2">
                    Price: <span class = "amount">{{ product.price | currency }}</span>
            </p>
    </div>

    <div class = "card-footerer p-1">
            <button class = "btn btn-sm btn-success w-100">Add</button>
    </div>
</div>

Эта проблема:

Эван, хотя проблем с компиляцией нет, консоль Chrome выдает ошибку:

Error trying to diff '[object Object]'. Only arrays and iterables are allowed

Где моя ошибка?

🤔 А знаете ли вы, что...
Синтаксис JavaScript схож с синтаксисом языка программирования Java, но они не связаны.


46
1

Ответ:

Решено

Причина в том, что https://dummyjson.com/products возвращает объект с полями products, total, skip, limit. Вероятно, вы имели в виду:

public getProducts(): Observable<Product[]>{
  return this.http.get<Product[]>(`${this.apiURL}/products`).pipe(map(response => response.products));
}

Или, если вы собираетесь ввести разбивку на страницы позже, вы можете объявить полную модель:

// models/product.ts
export interface ProductResponse {
  products: Product[];
  total: number;
  skip: number;
  limit: number;
}

...

// product.service.ts
public getProducts(): Observable<ProductResponse>{
  return this.http.get<ProductResponse>(`${this.apiURL}/products`);
}

...

// products-list.component.ts
productResponse: ProductResponse;

ngOnInit(): void {
 this.ProductService.getProducts().subscribe((response) => (this.productResponse = response));
}

...

// products-list.component.html
<ng-container *ngIf = "productResponse">
  <div class = "row">
    <div *ngFor = "let product of productResponse.products">