Angular http.get返回嵌套数据结构,ngFor无法渲染的解决办法
问题描述
当前Angular项目中,ColorService声明返回Observable<Color[]>,但实际API返回的是包含colors子数组的对象。组件订阅后用Object.values(colors)处理数据,导致HTML模板中*ngFor无法正确遍历,无法获取color.name。
服务代码
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { Color } from '../model/color'; import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: "root" }) export class ColorService { private productsUrl = 'http://localhost:5500/colors/'; constructor(private http: HttpClient) { } getColors(): Observable<Color[]> { var colors = this.http.get<Color[]>(this.productsUrl + "all"); return colors; } }
组件代码
ngOnInit(): void { this.colorsService.getColors() .subscribe((colors) => { this.colors = Object.values(colors); this.colors.sort((a,b) => a.name.localeCompare(b.name)); console.log(colors); }, err => { this.displaySpinner = false; }, () => { this.displaySpinner = false; }); }
Color接口定义
export interface Color { id: number; number: string; name: string; imagePath: string; category: string; color: string; brand: string; }
API实际返回结构
{ colors: [ { id: 1, number: 159, name: 'glamorous peach', imagePath: '/src/assets/img/colors/color104.jpeg', category: 'summer', color: 'orange', brand: 'Pink Gellac' } ] }
HTML模板代码
<mat-grid-tile *ngFor="let color of colors"> <mat-card class="example-card" style="width: 95%; border-radius:15px; box-shadow: 4px 4px 6px -1px rgba(0,0,0,0.15);"> <mat-card-content> <mat-grid-list cols="1" rowHeight="250"> <mat-grid-tile class="tile" style="overflow:auto;"> <div class="wrapper"> <p>{{color.name}}</p> </div> </mat-grid-tile> </mat-grid-list> </mat-card-content> </mat-card> </mat-grid-tile>
解决方案
方法一:修正服务层的类型与数据处理(推荐)
服务层当前的类型声明与API实际返回不匹配,需先定义API返回结构的接口,再提取目标数组:
- 新增API返回结构接口:
// 可放在color.ts或单独的response.ts文件中 export interface ColorResponse { colors: Color[]; }
- 修改
ColorService的getColors方法:
import { map } from 'rxjs/operators'; // ...其他代码不变 getColors(): Observable<Color[]> { return this.http.get<ColorResponse>(this.productsUrl + "all") .pipe( map(response => response.colors) // 提取colors数组 ); }
- 组件中修正数据赋值逻辑:
ngOnInit(): void { this.colorsService.getColors() .subscribe((colors) => { this.colors = colors; // 直接接收Color数组 this.colors.sort((a,b) => a.name.localeCompare(b.name)); console.log(colors); }, err => { this.displaySpinner = false; }, () => { this.displaySpinner = false; }); }
方法二:直接在组件中修正数据处理
如果不想改动服务层,可直接在组件订阅时正确提取数组:
将组件中的this.colors = Object.values(colors);替换为:
this.colors = colors.colors; // 直接取返回对象中的colors数组
问题根源说明
之前用Object.values(colors)会把API返回的{colors: [...]}对象的所有值提取出来,得到一个包含数组的数组(即[[color1, color2,...]]),此时*ngFor遍历的是外层数组的每一项(也就是整个colors数组),所以模板中的color是数组而非单个Color对象,自然无法获取name属性。
内容的提问来源于stack exchange,提问作者Amber Akkermans
相关产品推荐
相关产品推荐

