如何为Formly中使用的Angular Material日期范围选择器设置默认值
解决Formly中Angular Material日期范围选择器默认值不同步的问题
核心问题在于Angular Material日期选择器绑定的是Date对象,而你设置的模型值是ISO格式字符串,二者类型不匹配导致组件无法正确渲染;另外直接修改模型对象可能没触发Formly的变更检测。以下是具体解决方法:
1. 自定义组件中处理值类型转换
如果你的自定义datepicker-range组件实现了ControlValueAccessor,需要在writeValue方法中把ISO字符串转为Date对象,同时在值变更时把Date对象转回ISO字符串同步到模型:
import { Component, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { MatDateRangeInput } from '@angular/material/datepicker'; @Component({ selector: 'app-datepicker-range', templateUrl: './datepicker-range.component.html', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DatepickerRangeComponent), multi: true, }, ], }) export class DatepickerRangeComponent implements ControlValueAccessor { onChange: any = () => {}; onTouched: any = () => {}; constructor(public dateRangeInput: MatDateRangeInput<any>) {} writeValue(value: { start: string | Date; end: string | Date }): void { if (!value) return; // 将ISO字符串转为Date对象供组件渲染 const convertedValue = { start: typeof value.start === 'string' ? new Date(value.start) : value.start, end: typeof value.end === 'string' ? new Date(value.end) : value.end, }; this.dateRangeInput.value = convertedValue; } registerOnChange(fn: any): void { this.onChange = fn; } registerOnTouched(fn: any): void { this.onTouched = fn; } onRangeChange(value: { start: Date; end: Date }) { // 将组件的Date对象转回ISO字符串同步到模型 this.onChange({ start: value.start?.toISOString(), end: value.end?.toISOString(), }); this.onTouched(); } }
对应的组件模板示例:
<mat-form-field> <mat-label>Date Range</mat-label> <mat-date-range-input [rangePicker]="picker" (valueChange)="onRangeChange($event)"> <input matStartDate placeholder="Start date"> <input matEndDate placeholder="End date"> </mat-date-range-input> <mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle> <mat-date-range-picker #picker></mat-date-range-picker> </mat-form-field>
2. 通过Formly字段配置的格式化器处理转换
如果不想修改自定义组件,可以在Formly字段配置中添加formatters(模型值转视图值)和parsers(视图值转模型值):
fields = [ { key: 'range', type: 'datepicker-range', props: { label: 'Date Range', }, // 把模型中的ISO字符串转为Date对象,供组件使用 formatters: [ (value) => ({ start: value?.start ? new Date(value.start) : null, end: value?.end ? new Date(value.end) : null, }), ], // 把组件返回的Date对象转回ISO字符串,同步到模型 parsers: [ (value) => ({ start: value?.start?.toISOString(), end: value?.end?.toISOString(), }), ], }, ];
3. 动态更新模型的正确方式
不要直接修改model.range,而是通过FormGroup的patchValue或setValue方法触发变更检测:
// 初始化或动态更新默认值时 this.form.patchValue({ range: { start: '2024-01-01T00:00:00.000Z', end: '2024-01-10T00:00:00.000Z', }, });
这样模型值的变更会通过Formly的机制同步到组件,同时类型转换也能确保组件正确渲染日期。
内容的提问来源于stack exchange,提问作者Mario
相关产品推荐
相关产品推荐

