自从 Angular/Material 从 5 升级到 6 后,自定义本机日期适配器不再有效
custom native date adapter no longer works since upgrade of Angular/Material from 5 to 6
我的 Angular 5 应用程序中有一个自定义日期适配器:
import {NativeDateAdapter} from "@angular/material";
import {Injectable} from "@angular/core";
@Injectable()
export class CustomDateAdapter extends NativeDateAdapter {
parse(value: any): Date | null {
if ((typeof value === 'string') && (value.indexOf('/') > -1)) {
const str = value.split('/');
return new Date(Number(str[2]), Number(str[1])-1, Number(str[0]), 12);
}
const timestamp = typeof value === 'number' ? value : Date.parse(value);
return isNaN(timestamp) ? null : new Date(timestamp);
}
format(date: Date, displayFormat: Object): string {
return date.getFullYear() + "-" + (date.getMonth() + 1).toString().padStart(2, '0') + "-" + date.getDate().toString().padStart(2, '0');
}
}
定义于app.module.ts
@NgModule({
imports: [...],
declarations: [...],
providers: [
...,
{ provide: DateAdapter, useClass: CustomDateAdapter }
],
bootstrap: [
AppComponent
]
})
export class AppModule {}
它工作正常,但是当升级 Angular/Material 到版本 6 时它停止了。这是我现在遇到的错误:
ERROR TypeError: Cannot read property 'TRIDENT' of undefined
at new NativeDateAdapter (native-date-adapter.ts:83)
at new CustomDateAdapter (custom.date.adapter.ts:5)
at _createClass (ng_module.ts:171)
at _createProviderInstance (ng_module.ts:143)
at resolveNgModuleDep (ng_module.ts:104)
at NgModuleRef_.get (refs.ts:502)
at resolveDep (provider.ts:416)
at createClass (provider.ts:276)
at createDirectiveInstance (provider.ts:135)
at createViewNodes (view.ts:303)
我遇到了类似的问题 CustomeDateAdapter in Angular Material 6 并尝试了推荐的修复方法,包括构造函数
constructor(matDateLocale: string) {
super(matDateLocale, new Platform());
}
现在它产生以下错误:
ERROR Error: StaticInjectorError(AppModule)[DateAdapter -> String]:
StaticInjectorError(Platform: core)[DateAdapter -> String]:
NullInjectorError: No provider for String!
at NullInjector.get (injector.ts:35)
at resolveToken (injector.ts:332)
at tryResolveToken (injector.ts:274)
at StaticInjector.get (injector.ts:154)
at resolveToken (injector.ts:332)
at tryResolveToken (injector.ts:274)
at StaticInjector.get (injector.ts:154)
at resolveNgModuleDep (ng_module.ts:124)
at _createClass (ng_module.ts:173)
at _createProviderInstance (ng_module.ts:143)
知道如何让它重新工作吗?
我使用 MomentDateAdapter
和自定义日期格式解决了这个问题。
import {NgModule} from "@angular/core";
import {AppComponent} from "./app.component";
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from "@angular/material";
import {MomentModule} from "ngx-moment";
import {MomentDateAdapter} from '@angular/material-moment-adapter';
export const ISO_FORMAT = {
parse: {
dateInput: 'LL',
},
display: {
dateInput: 'YYYY-MM-DD',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM YYYY',
},
};
@NgModule({
imports: [
MomentModule,
...
],
declarations: [
AppComponent,
...
],
providers: [
{provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]},
{provide: MAT_DATE_FORMATS, useValue: ISO_FORMAT},
...
],
bootstrap: [
AppComponent
]
})
export class AppModule {}
不要使用moment
阅读documentation。
有关如何使用自定义日期适配器的简化示例。
自定义日期适配器:
import { Platform } from '@angular/cdk/platform';
import { DatePipe } from '@angular/common';
import { Inject, Injectable, Optional } from '@angular/core';
import { MAT_DATE_LOCALE, NativeDateAdapter } from '@angular/material/core';
@Injectable()
export class CustomDateAdapter extends NativeDateAdapter {
constructor(@Optional() @Inject(MAT_DATE_LOCALE) matDateLocale: string, platform: Platform) {
super(matDateLocale, platform);
}
format(date: Date): string {
// todo implement logic
return new DatePipe(this.locale).transform(date, 'MMMM YYYY');
}
}
在组件中的用法:
import { Platform } from '@angular/cdk/platform';
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { FormControl } from '@angular/forms';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
import { MatDatepicker } from '@angular/material/datepicker';
import { CustomDateAdapter } from './CustomDateAdapter';
export const MY_FORMATS = {
parse: {
dateInput: 'MMMM YYYY',
},
display: {
dateInput: 'MMMM YYYY',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM YYYY',
},
};
@Component({
selector: 'app-month-picker',
templateUrl: './month-picker.component.html',
styleUrls: ['./month-picker.component.scss'],
providers: [
{
provide: DateAdapter,
useClass: CustomDateAdapter,
deps: [MAT_DATE_LOCALE, Platform],
},
{ provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
],
})
export class YourComponent
我的 Angular 5 应用程序中有一个自定义日期适配器:
import {NativeDateAdapter} from "@angular/material";
import {Injectable} from "@angular/core";
@Injectable()
export class CustomDateAdapter extends NativeDateAdapter {
parse(value: any): Date | null {
if ((typeof value === 'string') && (value.indexOf('/') > -1)) {
const str = value.split('/');
return new Date(Number(str[2]), Number(str[1])-1, Number(str[0]), 12);
}
const timestamp = typeof value === 'number' ? value : Date.parse(value);
return isNaN(timestamp) ? null : new Date(timestamp);
}
format(date: Date, displayFormat: Object): string {
return date.getFullYear() + "-" + (date.getMonth() + 1).toString().padStart(2, '0') + "-" + date.getDate().toString().padStart(2, '0');
}
}
定义于app.module.ts
@NgModule({
imports: [...],
declarations: [...],
providers: [
...,
{ provide: DateAdapter, useClass: CustomDateAdapter }
],
bootstrap: [
AppComponent
]
})
export class AppModule {}
它工作正常,但是当升级 Angular/Material 到版本 6 时它停止了。这是我现在遇到的错误:
ERROR TypeError: Cannot read property 'TRIDENT' of undefined
at new NativeDateAdapter (native-date-adapter.ts:83)
at new CustomDateAdapter (custom.date.adapter.ts:5)
at _createClass (ng_module.ts:171)
at _createProviderInstance (ng_module.ts:143)
at resolveNgModuleDep (ng_module.ts:104)
at NgModuleRef_.get (refs.ts:502)
at resolveDep (provider.ts:416)
at createClass (provider.ts:276)
at createDirectiveInstance (provider.ts:135)
at createViewNodes (view.ts:303)
我遇到了类似的问题 CustomeDateAdapter in Angular Material 6 并尝试了推荐的修复方法,包括构造函数
constructor(matDateLocale: string) {
super(matDateLocale, new Platform());
}
现在它产生以下错误:
ERROR Error: StaticInjectorError(AppModule)[DateAdapter -> String]:
StaticInjectorError(Platform: core)[DateAdapter -> String]:
NullInjectorError: No provider for String!
at NullInjector.get (injector.ts:35)
at resolveToken (injector.ts:332)
at tryResolveToken (injector.ts:274)
at StaticInjector.get (injector.ts:154)
at resolveToken (injector.ts:332)
at tryResolveToken (injector.ts:274)
at StaticInjector.get (injector.ts:154)
at resolveNgModuleDep (ng_module.ts:124)
at _createClass (ng_module.ts:173)
at _createProviderInstance (ng_module.ts:143)
知道如何让它重新工作吗?
我使用 MomentDateAdapter
和自定义日期格式解决了这个问题。
import {NgModule} from "@angular/core";
import {AppComponent} from "./app.component";
import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE} from "@angular/material";
import {MomentModule} from "ngx-moment";
import {MomentDateAdapter} from '@angular/material-moment-adapter';
export const ISO_FORMAT = {
parse: {
dateInput: 'LL',
},
display: {
dateInput: 'YYYY-MM-DD',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM YYYY',
},
};
@NgModule({
imports: [
MomentModule,
...
],
declarations: [
AppComponent,
...
],
providers: [
{provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]},
{provide: MAT_DATE_FORMATS, useValue: ISO_FORMAT},
...
],
bootstrap: [
AppComponent
]
})
export class AppModule {}
不要使用moment
阅读documentation。
有关如何使用自定义日期适配器的简化示例。
自定义日期适配器:
import { Platform } from '@angular/cdk/platform';
import { DatePipe } from '@angular/common';
import { Inject, Injectable, Optional } from '@angular/core';
import { MAT_DATE_LOCALE, NativeDateAdapter } from '@angular/material/core';
@Injectable()
export class CustomDateAdapter extends NativeDateAdapter {
constructor(@Optional() @Inject(MAT_DATE_LOCALE) matDateLocale: string, platform: Platform) {
super(matDateLocale, platform);
}
format(date: Date): string {
// todo implement logic
return new DatePipe(this.locale).transform(date, 'MMMM YYYY');
}
}
在组件中的用法:
import { Platform } from '@angular/cdk/platform';
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { FormControl } from '@angular/forms';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from '@angular/material/core';
import { MatDatepicker } from '@angular/material/datepicker';
import { CustomDateAdapter } from './CustomDateAdapter';
export const MY_FORMATS = {
parse: {
dateInput: 'MMMM YYYY',
},
display: {
dateInput: 'MMMM YYYY',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM YYYY',
},
};
@Component({
selector: 'app-month-picker',
templateUrl: './month-picker.component.html',
styleUrls: ['./month-picker.component.scss'],
providers: [
{
provide: DateAdapter,
useClass: CustomDateAdapter,
deps: [MAT_DATE_LOCALE, Platform],
},
{ provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
],
})
export class YourComponent