Angular Material日期选择器获取字符串而非对象toString值的解决方案
解决Angular Material Datepicker组件表单取值为日期对象toString的问题
你当前的问题源于matDatepicker绑定的是原生Date对象,ngModelChange触发时传递的是Date实例,表单最终存储该对象后,调用toString()就会得到类似Wed May 10 2023 00:00:00 GMT+0200的结果。以下是无需依赖已废弃Moment.js的两种替代方案:
方案1:使用Angular内置DatePipe格式化输出
Angular自带的DatePipe可直接完成日期格式化,步骤如下:
- 在组件中注入
DatePipe - 修改
ngModelChange处理逻辑,将Date对象格式化为目标字符串后再传递给onChange - 处理
writeValue方法,将传入的格式化字符串转回Date对象用于回显
修改后的TypeScript代码
import { Component, forwardRef, Input } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { DatePipe } from '@angular/common'; @Component({ selector: 'm6smart-form-datepicker', templateUrl: './form-datepicker.component.html', styleUrls: ['./form-datepicker.component.scss'], providers: [ DatePipe, { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FormDatepickerComponent), multi: true, }, ], }) export class FormDatepickerComponent implements ControlValueAccessor { @Input() formInput!: FormDatepickerInput; onChange: any = () => {}; onTouch: any = () => {}; value: Date | string | undefined; // 调整类型兼容Date和字符串 disabled: boolean = false; private readonly dateFormat = 'yyyy-MM-dd'; // 定义目标格式 constructor(private datePipe: DatePipe) {} writeValue(obj: any): void { // 回显时将字符串转为Date对象 this.value = typeof obj === 'string' ? new Date(obj) : obj; } registerOnChange(fn: any): void { this.onChange = fn; } registerOnTouched(fn: any): void { this.onTouch = fn; } setDisabledState(isDisabled: any): void { this.disabled = isDisabled; } // 处理日期变更,格式化后传递给表单 onDateChange(event: Date): void { const formattedDate = this.datePipe.transform(event, this.dateFormat); this.onChange(formattedDate); this.value = event; this.onTouch(); } }
修改后的HTML代码
将ngModelChange绑定到自定义处理方法:
<mat-form-field (click)="picker.open()" appearance="fill"> <mat-label>{{ formInput.label }}</mat-label> <input matInput [matDatepicker]="picker" [(ngModel)]="value" (ngModelChange)="onDateChange($event)" [required]="formInput.required" [disabled]="formInput.disabled || disabled" autocomplete="off" /> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-datepicker #picker [disabled]="formInput.disabled || disabled"></mat-datepicker> </mat-form-field>
方案2:自定义日期适配器与格式器(全局统一格式)
若需在整个应用中统一日期格式,推荐使用Angular Material提供的DateAdapter和MAT_DATE_FORMATS,完全基于原生Date实现:
1. 创建自定义日期适配器
import { NativeDateAdapter } from '@angular/material/core'; export class CustomDateAdapter extends NativeDateAdapter { override format(date: Date, displayFormat: Object): string { // 定义全局输出格式 const year = date.getFullYear(); const month = this._twoDigit(date.getMonth() + 1); const day = this._twoDigit(date.getDate()); return `${year}-${month}-${day}`; } private _twoDigit(num: number): string { return num < 10 ? '0' + num : num.toString(); } }
2. 配置自定义日期格式
import { MAT_DATE_FORMATS } from '@angular/material/core'; export const CUSTOM_DATE_FORMATS = { parse: { dateInput: 'yyyy-MM-dd', // 解析输入的格式 }, display: { dateInput: 'yyyy-MM-dd', // 输入框显示的格式 monthYearLabel: 'yyyy MMM', dateA11yLabel: 'yyyy-MM-dd', monthYearA11yLabel: 'yyyy MMMM', }, };
3. 在模块中提供配置
在共享组件所在模块添加提供者:
import { NgModule } from '@angular/core'; import { MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core'; import { CustomDateAdapter } from './custom-date-adapter'; import { CUSTOM_DATE_FORMATS } from './custom-date-formats'; @NgModule({ ... providers: [ { provide: DateAdapter, useClass: CustomDateAdapter }, { provide: MAT_DATE_FORMATS, useValue: CUSTOM_DATE_FORMATS }, // 可选:设置本地化,如中文 // { provide: MAT_DATE_LOCALE, useValue: 'zh-CN' } ], }) export class SharedModule {}
4. 调整组件逻辑
此时ngModelChange会直接返回格式化后的字符串,只需确保writeValue兼容字符串和Date对象:
writeValue(obj: any): void { this.value = typeof obj === 'string' ? new Date(obj) : obj; }
内容的提问来源于stack exchange,提问作者Mark116
相关产品推荐
相关产品推荐

