Angular报错NG02100:DatePipe无效日期参数转换问题排查
Angular DatePipe 报错 NG02100 排查修复
异常现象
异常信息:NG02100: InvalidPipeArgument: 'Unable to convert "Wed Jun 29 2022 10:19:00 GM" into a date' for pipe 'DatePipe' - Angular
每次点击项目条目时都会抛出该错误,无法定位触发异常的具体位置,初步判断和字符串转日期逻辑相关,但未找到根因。
关联代码
组件逻辑代码
@Component({ selector: 'bookmark-history', templateUrl: './history.component.html', styleUrls: ['./history.component.scss'] }) export class HistoryComponent{ Contents$:Observable<History[]>; ContentsInOrder$:Observable<Content[]>; Histories$=this.facade.Histories$; histo:History[]; Date= new Date; showTrash = false; constructor(private historyService : HistoryService, private contentService : ContentService, private _snackBar: MatSnackBar, private facade:HistoryFacade, private dialogService:DialogService, private dialog:MatDialog) { this.Contents$=this.contentService.getContent(); this.ContentsInOrder$=this.contentService.getContentInOrder(); this.ContentsInOrder$ = this.ContentsInOrder$.pipe(map((result => result.sort((a,b) => b.points - a.points)))) this.Histories$ = this.Histories$.pipe(map((rallies => rallies.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())))) this.facade.loadHistoryList(); this.Histories$.subscribe(history => { this.histo = history as History[]; }) } onDeleteHistory(history:History){ this.facade.deleteHistory(history); } onAddHistory(content:Content){ const histo : History ={ id : Math.floor(Math.random() * 999999999), SNS:content.SNS, title:content.title, DMC:content.DMC, date : new Date(), showTrash : false } this.facade.addHistory(histo); this.facade.loadHistoryList(); } onDeleteAll(){ this.historyService.deleteAllHistory(this.histo); } @Output() click: EventEmitter<void> = new EventEmitter(); onclick(){ this.click.emit(); } openDialog(){ this.dialog.open(DialogComponent); } } @Pipe({ name: 'groupByDay' }) export class GroupByDayPipe implements PipeTransform { constructor(private facade:HistoryFacade) {} Histories$=this.facade.Histories$; transform(items: any[]): any[] { const groups = items.reduce((groups, game) => { const date = game.date.toString().split('T')[0]; if (!groups[date]) { groups[date] = []; } groups[date].push(game); return groups; }, {}); const groupArrays = Object.entries(groups); console.log(groupArrays); return groupArrays; } }
组件模板代码
<mat-tab-group mat-align-tabs="start" class="leftSide"> <mat-tab label="Recent Document View"> <div class="scroll"> <div mat-subheader *ngIf="(Histories$ | async).length===0">The documents you visit will show here</div> <ng-container *ngIf="Histories$ | async"> <ng-container *ngFor="let group of Histories$ | async | groupByDay"> <strong>{{ group[0] | date: 'EEEE, MMMM d, YYYY' }}</strong> <br /> <br /> <div *ngFor="let history of group[1]"> <mat-list-item class="historyClicking" (mouseover)="history.showTrash=true" (mouseout)="history.showTrash=false" (click)="onclick()"> <div class="block"> <div matList>{{history.SNS}}</div> <div matList>{{history.title}}</div> <div matList>{{history.DMC}}</div> <div matLine class="onit" > <button *ngIf="history.showTrash" mat-icon-button (click)="onDeleteHistory(history)"> <mat-icon>delete_outline</mat-icon> </button> <div *ngIf="!history.showTrash">{{history.date | date:"mediumTime"}}</div> </div> </div> </mat-list-item> </div> </ng-container> </ng-container> </div> </mat-tab> </mat-tab-group>
根因定位
报错和你怀疑的*ngFor="let history of group[1]"代码行无关,核心问题是传入DatePipe的日期值是非法非标准格式:
- GroupByDayPipe里生成分组key的逻辑错误:当
game.date是Date对象时,调用toString()返回的是类似Wed Jun 29 2022 10:19:00 GMT+0800 (中国标准时间)的本地时间字符串,这个字符串里根本没有字符T,用split('T')[0]切割拿到的是残缺的字符串(就是报错里的Wed Jun 29 2022 10:19:00 GM),把这个残缺字符串传给{{ group[0] | date: 'EEEE, MMMM d, YYYY' }}的DatePipe时,就会抛出解析失败的错误。 - 模板中多次重复订阅
Histories$ | async,会导致流多次执行,放大异常出现的概率。
修复方案
- 重写GroupByDayPipe的分组key生成逻辑,不要依赖
toString()切割,统一生成标准YYYY-MM-DD格式的日期key:
transform(items: any[]): any[] { const groups = items.reduce((groups, game) => { // 先统一转Date对象做兼容,不管传入的是时间戳、字符串还是Date实例 const gameDate = new Date(game.date); // 生成标准YYYY-MM-DD格式的分组key,确保DatePipe可以正常解析 const dateKey = `${gameDate.getFullYear()}-${String(gameDate.getMonth() + 1).padStart(2, '0')}-${String(gameDate.getDate()).padStart(2, '0')}`; if (!groups[dateKey]) { groups[dateKey] = []; } groups[dateKey].push(game); return groups; }, {}); return Object.entries(groups); }
- 优化模板的async订阅,用
as关键字存局部变量,避免重复订阅触发冗余计算:
<ng-container *ngIf="Histories$ | async as histories"> <ng-container *ngFor="let group of histories | groupByDay"> <!-- 原有模板内容不变 --> </ng-container> </ng-container>
- 所有传给DatePipe的日期值,确保是Angular支持的三类合法值:Date实例、毫秒级时间戳、ISO 8601标准日期字符串(如
2022-06-29T10:19:00.000Z),不要传入非标准的残缺日期字符串。
内容的提问来源于stack exchange,提问作者Picolo
相关产品推荐
相关产品推荐

