我们使用标准的日期选择器组件,该组件来自Angular材料(第9.1.2版),如下所示:
<mat-form-field>
<mat-label i18n>Date of birth</mat-label>
<input matInput [matDatepicker]="picker" formControlName="dateOfBirth" />
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
日期采用ISO格式,例如1979-12-02
。绑定到表单并显示后,就像在整个表单上调用getRawValue
一样,可以将其取回。但是,这会以javascript Date
的形式返回日期,然后将其转换为字符串并以“完整” ISO格式发送至后端,例如1979-12-02TXX:00:00.000Z
,这会破坏联系人/ API。
如果我们使用MatMomentDateModule
而不是MatNativeDateModule
,则会得到一个js日期(而不是javascript Date
),但这对格式化没有帮助。
是否可以将控件的原始值绑定为字符串而不是日期?最好不要将组件包装在ControlValueAccessor
中?也许是自定义的DateAdapter
?
答案 0 :(得分:1)
是的,您应该实现自定义DateAdapter
以使用短ISO日期字符串。
基本上,您只需要创建扩展DateAdapter的类并实现以下方法:
abstract getYear(date: D): number;
abstract getMonth(date: D): number;
abstract getDate(date: D): number;
abstract getDayOfWeek(date: D): number;
abstract getMonthNames(style: 'long' | 'short' | 'narrow'): string[];
abstract getDateNames(): string[];
abstract getDayOfWeekNames(style: 'long' | 'short' | 'narrow'): string[];
abstract getYearName(date: D): string;
abstract getFirstDayOfWeek(): number;
abstract getNumDaysInMonth(date: D): number;
abstract clone(date: D): D;
abstract createDate(year: number, month: number, date: number): D;
abstract today(): D;
abstract parse(value: any, parseFormat: any): D | null;
abstract format(date: D, displayFormat: any): string;
abstract addCalendarYears(date: D, years: number): D;
abstract addCalendarMonths(date: D, months: number): D;
abstract addCalendarDays(date: D, days: number): D;
abstract toIso8601(date: D): string;
abstract isDateInstance(obj: any): boolean;
abstract isValid(date: D): boolean;
abstract invalid(): D;
Angular团队提供了两个很好的例子:MomentDateAdapter和NativeDateAdapter。
实施适配器后,您需要将其添加到模块或组件中,如下所示:
providers: [
{provide: DateAdapter, useClass: YourISODateAdapter, deps: [...]}
],
答案 1 :(得分:1)
我已经分析了 MatDatepickerInputBase 源代码,目前没有选项可以配置您希望在相关 FormControl 中具有哪种类型或格式的值。
因此,基于覆盖类方法的 this idea,我已将此代码放在 app.module 中,并以我想要的格式 YYYY-MM-DD
获取日期作为字符串值。当用户手动输入日期或在日历组件中选择日期以及日期是否有效时,字符串将传递给控制。我也使用自己的 DateAdapter 重写类,但它与此问题无关,因为 DateAdapter 仅通过重写 parse() 和 format() 方法来格式化日期以在 MatDatepickerInput 控件中显示。
const customFormatDate = (date: Date) => formatDate(date, 'yyyy-MM-dd', 'en');
MatDatepickerInput.prototype._registerModel = function(model: any): void {
this._model = model;
this._valueChangesSubscription.unsubscribe();
if (this._pendingValue) {
this._assignValue(this._pendingValue);
}
this._valueChangesSubscription = this._model.selectionChanged.subscribe(event => {
if (this._shouldHandleChangeEvent(event)) {
const value = this._getValueFromModel(event.selection);
this._lastValueValid = this._isValidValue(value);
// this._cvaOnChange(value);
this._cvaOnChange(customFormatDate(value));
this._onTouched();
this._formatValue(value);
this.dateInput.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
this.dateChange.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
}
});
};
MatDatepickerInput.prototype._onInput = function(value: string) {
const lastValueWasValid = this._lastValueValid;
let date = this._dateAdapter.parse(value, this._dateFormats.parse.dateInput);
this._lastValueValid = this._isValidValue(date);
date = this._dateAdapter.getValidDateOrNull(date);
if (!this._dateAdapter.sameDate(date, this.value)) {
this._assignValue(date);
//this._cvaOnChange(date);
this._cvaOnChange(customFormatDate(date));
this.dateInput.emit(new MatDatepickerInputEvent(this, this._elementRef.nativeElement));
} else {
// Call the CVA change handler for invalid values
// since this is what marks the control as dirty.
if ((value === '') || value && !this.value) {
this._cvaOnChange(value);
}
if (lastValueWasValid !== this._lastValueValid) {
this._validatorOnChange();
}
}
};
答案 2 :(得分:0)
在将对象发送到api之前,先将其字符串化,如下所示:-
const req = JSON.stringify(reqObj, (key: any, value: any) => {
if (JSON.parse(JSON.stringify(moment(value))) === value) {
return moment(value).format("yyyy/MM/DD");
} else {
return value;
}
});
并将请求发送到api。这会将您的requet对象中的任何时刻日期转换为所需的格式。
答案 3 :(得分:0)
此处日期对象的类型已更改,并且使用补丁值方法已更新了formcontrol值,因此当您从后端api获得响应时,它将自动将UI中的数据绑定。使用moment.js,您可以找到[Using Moment.js] 1
HTML:
<form [formGroup]="frmStepOne" (ngSubmit)="onSubmit()">
<div>
<mat-form-field>
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker" formControlName="dateValue" (dateChange)="date($event)">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
TS:
convertDate:String;
constructor(private _formBuilder: FormBuilder) {
this.frmStepOne = this._formBuilder.group({
dateValue:['']
});
date(e) {
this.convertDate = new Date(e.target.value).toISOString().substring(0, 10);
this.frmStepOne.get('dateValue').patchValue(this.convertDate, {
onlyself: true
})
}
onSubmit(){
console.log(this.frmStepOne.value.dateValue)
console.log(typeof(this.convertDate));
}
答案 4 :(得分:0)
您可以创建HttpInterceptor
,然后遍历请求正文以将所有datetime属性转换为所需的格式
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { DatePipe } from '@angular/common';
import { isArray } from 'util';
@Injectable()
export class HttpDatetimeInterceptor implements HttpInterceptor {
constructor(private datePipe: DatePipe) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.convertDatetimeToStringFormate(request.body);
return next.handle(request);
}
convertDatetimeToStringFormate(body) {
for (let [key] of Object.entries(body)) {
if (isArray(body[key])) {
for (let prop of body[key]) {
this.convertDatetimeToStringFormate(prop);
}
}
// Check if property is date
if (typeof body[key].getMonth === 'function') {
body[key] = this.datePipe.transform(body[key], 'yyyy/MM/dd');
}
}
}
}
答案 5 :(得分:0)
使用带有moment的土星日期选择器来解析日期。抱歉,现在没有时间摘录。
dateChanged(event: MatDatepickerInputEvent<DateRange>) {
if (event.value) {
const { begin, end } = event.value;
this.store.dispatch(
setDateRangeFilterAction({
begin: moment(begin).tz("UTC").toISOString(),
end: moment(end)
.add(1, "days")
.toISOString()
})
);
} else {
this.store.dispatch(setDateRangeFilterAction({ begin: null, end: null }));
}
}
<mat-form-field>
<input
matInput
class="date-input"
placeholder="Select a date range"
name="range-picker"
[satDatepicker]="picker"
[value]="creationTimeFilter$ | async"
(dateChange)="dateChanged($event)"
/>
<sat-datepicker-toggle matSuffix [for]="picker">
<mat-icon matDatepickerToggleIcon>keyboard_arrow_down</mat-icon>
</sat-datepicker-toggle>
<sat-datepicker #picker [rangeMode]="true"></sat-datepicker>
</mat-form-field>