Angular 13 应用中出现 "only arrays and iterables are allowed" 错误的原因是什么?

What causes the "only arrays and iterables are allowed" error in this Angular 13 app?

我正在开发一个电子商务应用程序,它的前端是在 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>

问题:

Evan 虽然没有编译问题,Chrome 控制台抛出错误:

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

我的错误在哪里?

原因是 https://dummyjson.com/products returns 具有字段 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">