如何使用 *ngFor 循环我的数据对象?
Posted
技术标签:
【中文标题】如何使用 *ngFor 循环我的数据对象?【英文标题】:How can I use *ngFor to loop my data object? 【发布时间】:2020-01-21 02:24:11 【问题描述】:这是我的“monthlyCalendar”对象:
"monthName": "September 2019",
"dateObjList":
"1":
"dayOfWeek": "0",
"isPublicHoliday": false,
.............
,
"2":
"dayOfWeek": "0",
"isPublicHoliday": true,
.............
,
.....................
这是我的组件.ts:
...........
ngOnInit()
this.monthlyCalendarService.getMonthlyCalendar(null, null).subscribe(
(res: MonthlyCalendar) =>
this.monthlyCalendar = res;
this.monthName = this.monthlyCalendar.monthName;
,
(error: Error) =>
alert('Something wrong when getting Monthly Calendar data.\n' + error.message);
,
);
.........
这是我每月的CalendarService.ts:
import Injectable from '@angular/core';
import HttpClient, HttpParams from '@angular/common/http';
import MonthlyCalendar from './monthly-calendar';
import Observable from 'rxjs';
import map, catchError from 'rxjs/operators';
@Injectable(
providedIn: 'root'
)
export class MonthlyCalendarService
constructor(private http: HttpClient)
getMonthlyCalendar(year: string, month: string): Observable<MonthlyCalendar>
const params = new HttpParams();
params.set('year', year);
params.set('month', month);
return this.http.get('backend/getMonthlyCalendar.php', params).pipe(map((res: MonthlyCalendar) => res));
/*
return this.http.get('backend/getMonthlyCalendar.php', params)
.pipe(map((res: MonthlyCalendar) => console.log('service:' + JSON.stringify(res)); return res; )
//, catchError(this.handleError)
);
*/
这是我的component.html:
...........
<td *ngFor="let dateObj of monthlyCalendar?.dateObjList|async" class="phCell">
<span *ngIf="dateObj.isPublicHoliday">PH</span>
</td>
...........
我想在 dateObj.isPublicHoliday 属性为 true 时显示 span 标签。
但是,浏览器提示我以下错误消息:
ERROR Error: InvalidPipeArgument: '[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]' for pipe 'AsyncPipe'
如果我也将“keyvalue”管道应用于 *ngFor,即
<td *ngFor="let dateObj of monthlyCalendar?.dateObjList|async|keyvalue" class="phCell">
我收到以下错误消息:
Error: InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe'
我怎样才能让它工作?
【问题讨论】:
access key and value of object using *ngFor的可能重复 【参考方案1】:最后,我整合你所有的想法来解决这个问题,
我修改了 component.ts 以将monthlyCalendar 对象更改为可观察。
monthlyCalendar: Observable<MonthlyCalendar>;
................
ngOnInit()
this.monthlyCalendar = this.monthlyCalendarService.getMonthlyCalendar(null, null);
然后我按照 Adrian 的建议创建了一个名为 toArray 的管道。 我将component.html修改如下
<td *ngFor="let dateObj of (monthlyCalendar|async)?.dateObjList|toArray " class="alignCenter phCell borderCell dateCell">
<span *ngIf=dateObj.isPublicHoliday>PH</span>
</td>
虽然正确显示“PH”,但浏览器提示“TypeError: Cannot read property 'dateObjList' of null”。 最后,下面的网页告诉我为什么安全导航运算符不能与异步管道一起使用。
Safe navigation operator on an async observable and pipe in Angular 2
所以,toArray 管道的最终版本如下:
import Pipe, PipeTransform from '@angular/core';
@Pipe(
name: 'toArray'
)
export class ToArrayPipe implements PipeTransform
transform(value, args: string[]): any
if (value != null)
return Object.values(value);
感谢您的所有帮助。
【讨论】:
【参考方案2】:丢失异步管道,您的每月日历不是异步可观察对象。您在订阅后手动分配它。
管道keyvalue
使用value
属性返回并带有2 个道具key
和value
的对象导航到您的对象。
检查管道keyvalue
中的value
属性
dateObj.value.isPublicHoliday
所以你的代码终于变成了
<td *ngFor="let dateObj of (monthlyCalendar)?.dateObjList|keyvalue" class="phCell">
<span *ngIf="dateObj.value.isPublicHoliday">PH</span>
</td>
编辑 2:
Angular 推荐的正确方式
如果你想在你的组件中像 observable 那样做
monthlyCalendar$: Observable<any>; //declare your observable to use in template (Use a custom Interface to have data type as your response)
ngOnInit()
this.monthlyCalendar$ = this.monthlyCalendarService.getMonthlyCalendar(null, null);
你的模板变成了
<td *ngFor="let dateObj of (monthlyCalendar$|async)?.dateObjList|keyvalue" class="phCell">
<span *ngIf="dateObj.value.isPublicHoliday">PH</span>
</td>
但要实现这一点,可能需要进行大量架构更改。但是您应该阅读更多关于显示来自 Angular 官方文档的服务数据的信息
查看类似模拟https://stackblitz.com/edit/angular-pfhzrd的示例
编辑 3:
尽管选择了这样的数据结构,但很有可能您必须再次实现排序算法。
您的服务可以这样修改 [注意]:建议服务器应该发送一个 dataObjList 数组而不是一个对象。
return this.http.get('backend/getMonthlyCalendar.php', params).pipe(map((res: MonthlyCalendar) =>
res.dateObjList = Object.values(res.dateObjList).reduce((list, date) => [...list, date], []);
//res.dateObjList.sort((a,b) => a.id - b.id); //Note you might lose your sort coming from backend so you need to sort it based on some key or anything
return res;
));
所以你的对象变成了如下所示的 dateObjList 数组
"monthName": "September 2019",
"dateObjList": [
"dayOfWeek": "0",
"isPublicHoliday": false,
.............
,
"dayOfWeek": "0",
"isPublicHoliday": true,
.............
,
.....................
]
那么你的模板就不需要键值了:
<td *ngFor="let dateObj of (monthlyCalendar$|async)?.dateObjList" class="phCell">
<span *ngIf="dateObj.isPublicHoliday">PH</span>
</td>
【讨论】:
浏览器提示如下错误: InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe' 我已经把服务和组件的源代码都包含了供大家参考。 似乎有人是对的,每月日历不是可观察的 @TheKNVB 检查更新的答案。虽然你应该直接将 observables 分配给这样的模板 stackblitz.com/edit/angular-pfhzrd 我不确定monthlyCalendar 是否是可观察的。我已将服务和组件添加到我的问题中以供参考。 它在错误的单元格中显示 PH。 “PH”应显示在单元格 14 中,但显示在单元格 6 中。【参考方案3】:问题是您的数据不是可观察的,并且您使用的是异步管道。如果 monthlyCalendar?.dateObjList
可以观察到,则异步管道可以工作。
<td *ngFor="let dateObj of monthlyCalendar?.dateObjList" class="phCell">
<span *ngIf="dateObj.isPublicHoliday">PH
</span>
</td>
否则你可以这样做。
<td *ngFor="let dateObj of (monthlyCalendar| async)?.dateObjList" class="phCell">
<span *ngIf="dateObj.isPublicHoliday">PH
</span>
</td>
您可以从here 了解更多信息
【讨论】:
【参考方案4】:试试这个方法
@Pipe(name: 'keys')
export class KeysPipe implements PipeTransform
transform(value, args:string[]) : any
let keys = [];
for (let key in value)
keys.push(key: key, value: value[key]);
return keys;
<td *ngFor="let dateObj of monthlyCalendar?.dateObjList|keys|async" class="phCell">
<span *ngIf="dateObj.isPublicHoliday">PH</span>
更多详情,请访问:How to display json object using *ngFor
【讨论】:
【参考方案5】:ngFor 迭代数组而不是对象,你可以将数据分配给数组
dates = Object.values(data.dateObjList);
然后你可以对日期数组进行 ngFor。
如果您想使用异步管道,您需要创建一个将对象转换为数组的管道。
import Pipe, PipeTransform from '@angular/core';
@Pipe(
name: 'toArray'
)
export class ToArrayPipe implements PipeTransform
transform(value: any): any
return Object.values(value);
并与它一起使用
*ngFor="let dateObj of (monthlyCalendar | async).dateObjList| toArray"
【讨论】:
我已经应用了keyvalue,但是你可以看到上面的错误信息。 monthlyCalendar 是可观察的吗?如果是这样,它应该按照命名标准命名为monthlyCalendar$,然后您需要使用 (monthlyCalendar | async).dateObjList | toArray 我不确定monthlyCalendar 是否可观察。我已将服务和组件添加到我的问题中。 我怎样才能使每月日历可观察? 而不是订阅您的服务,您将返回的 observable 分配给属性monthlyCalendar$ = this.monthlyCalendarService.getMonthlyCalendar(null, null) 然后您可以在该属性上使用异步管道。无需订阅。以上是关于如何使用 *ngFor 循环我的数据对象?的主要内容,如果未能解决你的问题,请参考以下文章