Angular 14中如何实现字符串日期列表与mat-datepicker双向绑定
Angular Material 日期选择器默认仅支持Date类型值的双向绑定,直接绑定MM/DD/YYYY格式字符串会出现值无法识别、选中日期后字段被覆写为Date对象的问题,以下两种方案都可以实现你要的效果,按需选择即可。
方案1:自定义日期适配器(推荐,无需改动原有数据结构)
这个方案会让日期选择器自动完成MM/DD/YYYY字符串和内部Date对象的双向转换,全程保持你的batch.date字段为字符串格式,不需要修改现有trek.batches的数据结构。
- 首先创建自定义日期适配器:
import { NativeDateAdapter } from '@angular/material/core'; import { Injectable } from '@angular/core'; @Injectable() export class StringDateAdapter extends NativeDateAdapter { // 组件内部Date对象转MM/DD/YYYY字符串,写回绑定字段 override format(date: Date, displayFormat: Object): string { const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const year = date.getFullYear(); return `${month}/${day}/${year}`; } // 绑定的MM/DD/YYYY字符串转组件需要的Date对象 override parse(value: any): Date | null { if (typeof value === 'string' && value.includes('/')) { const [month, day, year] = value.split('/'); return new Date(Number(year), Number(month) - 1, Number(day)); } return value ? new Date(value) : null; } } - 在使用日期选择器的组件中注册适配器和日期格式配置:
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; import { StringDateAdapter } from './string-date-adapter'; // 对齐MM/DD/YYYY显示格式 const CUSTOM_DATE_FORMATS = { parse: { dateInput: 'MM/DD/YYYY' }, display: { dateInput: 'MM/DD/YYYY', monthYearLabel: 'MMM YYYY', dateA11yLabel: 'LL', monthYearA11yLabel: 'MMMM YYYY', }, }; @Component({ selector: 'your-component', templateUrl: './your-component.html', // 组件级注册,不会影响其他页面的日期选择器 providers: [ { provide: DateAdapter, useClass: StringDateAdapter }, { provide: MAT_DATE_FORMATS, useValue: CUSTOM_DATE_FORMATS } ] }) - 原有模板代码不需要做任何修改,
[(ngModel)]="batch.date"即可正常完成双向绑定。
方案2:拆分ngModel手动转换(轻量场景适用)
如果日期选择器只在当前列表使用,不想额外写适配器,可以把[(ngModel)]语法糖拆分为属性绑定和事件绑定,手动做格式转换。
- 修改模板代码:
<div *ngFor="let batch of trek.batches; let i = index" [attr.data-index]="i"> <mat-form-field appearance="standard" class="ml10"> <mat-label>Date</mat-label> <input matInput [matDatepicker]="batchDatePicker" name="batchDate_{{i}}" [ngModel]="parseStrToDate(batch.date)" (ngModelChange)="batch.date = formatDateToStr($event)" > <mat-hint>MM/DD/YYYY</mat-hint> <mat-datepicker-toggle matSuffix [for]="batchDatePicker"></mat-datepicker-toggle> <mat-datepicker #batchDatePicker></mat-datepicker> </mat-form-field> </div> - 在组件类中添加两个转换方法:
// MM/DD/YYYY字符串转Date供选择器识别 parseStrToDate(dateStr: string): Date | null { if (!dateStr) return null; const [month, day, year] = dateStr.split('/'); return new Date(Number(year), Number(month) - 1, Number(day)); } // 选择器返回的Date转MM/DD/YYYY字符串存回字段 formatDateToStr(date: Date): string { if (!date) return ''; const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${month}/${day}/${date.getFullYear()}`; }
注意:不要在模板中直接写内联箭头函数做转换,会触发变更检测死循环,转换逻辑必须定义在组件类中。
补充说明
- 两种方案都不会改动原有
batch.date的字符串格式,后续接口提交、数据处理不需要额外做格式转换 - 如果项目中所有日期选择器都使用
MM/DD/YYYY字符串格式,可以把自定义适配器注册到根模块,全局生效无需重复配置 - 建议添加日期格式校验,避免
13/01/2024这类非法日期值导致解析失败
内容的提问来源于stack exchange,提问作者Prem Parihar
相关产品推荐
相关产品推荐

