Angular 2 Material 2日期选择器日期格式化

62

我不知道如何更改 Material 2 Datepicker 的日期格式。我已经阅读了文档,但我不明白我实际需要做什么。Datepicker 默认提供的输出日期格式是: 6/9/2017

我想要的是将格式更改为像 9-Jun-2017 或其他任何格式。

文档https://material.angular.io/components/component/datepicker对我没有帮助。


以下是一个示例:https://gist.github.com/fxck/efe4ccff13d99ee9a2dcf82365909168 - Robin Dijkhof
1
谢谢您的帮助,但我不想使用自己的日期提供程序,我只想根据文档更改日期格式,文档中写道可以使用本地日期适配器。 - Igor Janković
17个回答

51

这是我为此找到的唯一解决方案:

首先,创建常量:

const MY_DATE_FORMATS = {
   parse: {
       dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
   },
   display: {
       // dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
       dateInput: 'input',
       monthYearLabel: {year: 'numeric', month: 'short'},
       dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
       monthYearA11yLabel: {year: 'numeric', month: 'long'},
   }
};

然后您需要扩展NativeDateAdapter:

export class MyDateAdapter extends NativeDateAdapter {
   format(date: Date, displayFormat: Object): string {
       if (displayFormat == "input") {
           let day = date.getDate();
           let month = date.getMonth() + 1;
           let year = date.getFullYear();
           return this._to2digit(day) + '/' + this._to2digit(month) + '/' + year;
       } else {
           return date.toDateString();
       }
   }

   private _to2digit(n: number) {
       return ('00' + n).slice(-2);
   } 
}

在格式函数中,您可以选择任何格式

最后一步是将其添加到模块提供程序中:

providers: [
    {provide: DateAdapter, useClass: MyDateAdapter},
    {provide: MD_DATE_FORMATS, useValue: MY_DATE_FORMATS},
],

就这样了。我无法相信没有一种简单的方式可以通过@Input更改日期格式,但让我们希望它将在 material 2 的某个未来版本中实现(目前处于beta 6)。


1
你能把它放在 Plunker 上吗?我按照你说的做了,但是没有起作用。 - Marcogomesr
1
我也遇到了同样的问题(beta.8)。 错误:未捕获(在承诺中):TypeError:无法读取未定义的“dateInput”属性。 - Robouste
@web2kx 我把上述内容应用到了 Plunkr 中,但似乎并没有按照预期工作,请告诉我 https://dev59.com/v1YO5IYBdhLWcg3wEdr5 - Kelum
9
FYI:MD_DATE_FORMATS 现已被 MAT_DATE_FORMATS 取代。 您可以这样导入它: import { DateAdapter, NativeDateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE } from "@angular/material/core"; - remborg
2
对于那些无法使此示例工作的人,请将 constructor() {super('en-US');} 添加到 MyDateAdapter 类中。 - crollywood
显示剩余7条评论

43

伊戈尔的答案对我没有用,所以我直接在 Angular 2 Material 的 GitHub 上提问,有人给了我一个可行的答案:

  1. 首先编写您自己的适配器:

  2. import { NativeDateAdapter } from "@angular/material";
    
    
    export class AppDateAdapter extends NativeDateAdapter {
    
        format(date: Date, displayFormat: Object): string {
    
            if (displayFormat === 'input') {
    
                const day = date.getDate();
                const month = date.getMonth() + 1;
                const year = date.getFullYear();
    
                return `${day}-${month}-${year}`;
            }
    
            return date.toDateString();
        }
    }
    
  3. 创建你的日期格式:

  4. export const APP_DATE_FORMATS =
    {
        parse: {
            dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
        },
        display: {
            dateInput: 'input',
            monthYearLabel: { year: 'numeric', month: 'numeric' },
            dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' },
            monthYearA11yLabel: { year: 'numeric', month: 'long' },
        }
    };
    
  5. 将这两个提供给您的模块

  6. providers: [
            {
                provide: DateAdapter, useClass: AppDateAdapter
            },
            {
                provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS
            }
        ]
    

更多信息在这里

编辑:对于那些输入手动时间格式被忽略的人,您可以按照以下方式覆盖NativeDateAdapterparse(value: any)函数。

parse(value: any): Date | null {
    const date = moment(value, 'DD/MM/YYYY');
    return date.isValid() ? date.toDate() : null;
}

因此,自定义适配器的最终形式将如下所示。

import { NativeDateAdapter } from "@angular/material";
import * as moment from 'moment';

export class AppDateAdapter extends NativeDateAdapter {

    format(date: Date, displayFormat: Object): string {
        if (displayFormat === 'input') {

            const day = date.getDate();
            const month = date.getMonth() + 1;
            const year = date.getFullYear();

            return `${day}/${month}/${year}`;
        }

        return date.toDateString();
    }

    parse(value: any): Date | null {
        const date = moment(value, environment.APP_DATE_FORMAT);
        return date.isValid() ? date.toDate() : null;
    }
}

2
由于ES6字符串模板的存在,建议使用它来大幅减少代码量。 - jarodsmk
@Robouste 这个部分有效。它提供了一个特定的格式,如“Fri 28 Jul 2017”,但如果您更改格式,则输入和日历仍然期望美国格式,即使您已经正确设置了区域设置。 - Vassilis Pits
1
@VassilisPits 尽管 native-date-adapter 的 format() 函数可以很好地输出日期格式,但是它的 parse() 函数却没有尝试过。https://github.com/angular/material2/blob/master/src/lib/core/datetime/native-date-adapter.ts 您可以重写 parse 函数以将日期转换回日期对象。这就是我用来解析 'de-DE' 格式日期 'dd.mm.yyyy' 为 Date() 对象的方法。 - Stephen
1
我相信现在应该是MAT_DATE_FORMATS而不是MD_了? - Gaspa79
2
谢谢,这对我有效,但是当我手动填写输入时,它仍然使用旧格式,你有解决办法吗? - Abdennacer Lachiheb
显示剩余3条评论

20

你只需要提供自定义的MAT_DATE_FORMATS即可。

export const APP_DATE_FORMATS = {
    parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}},
    display: {
        dateInput: {month: 'short', year: 'numeric', day: 'numeric'},
        monthYearLabel: {year: 'numeric'}
    }
};

并将其添加到提供者列表中。

providers: [{
   provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS
}]

工作中的 代码


6
dd-mm-yyyy 是怎样的日期? - Prashant Pimpale
将此内容集成到我的主要 app.component.ts 中,子组件中运行得很好。 - TDP
1
我必须在子组件中单独添加它才能正常工作。 - Suhail Akhtar
@PrashantPimpale 看起来你需要编写自己的适配器。 - laike9m

12

对我有用的解决方法是:

my.component.html:

<md-input-container>
  <input mdInput disabled [ngModel]="someDate | date:'d-MMM-y'" >
  <input mdInput [hidden]='true' [(ngModel)]="someDate"  
[mdDatepicker]="picker">
  <button mdSuffix [mdDatepickerToggle]="picker"></button>
</md-input-container>
<md-datepicker #picker></md-datepicker> 

my.component.ts :


@Component({...
})
export class MyComponent implements OnInit {
  ....
  public someDate: Date;
  ...

现在您可以选择最适合您的格式(例如 'd-MMM-y')。


1
在beta8上对我有效。然而,使用此选项会失去在文本框中输入以编辑日期的能力。 - Michael Lang
1
是的。但这不是一个大问题,如果用户开始输入日期而不知道您期望的确切格式,那么问题就更大了。 - luka martinovic
1
如果您的输入与响应式表单绑定,可以像这样使用:```<form [formGroup]="myForm"> <input [value]="myForm.get('date').value | date: 'MM/YYYY'" formControlName="date"></form>``` - RedDree

11

很有可能您已经使用过一个库,它可以为您提供在JavaScript中操作(解析、验证、显示等)日期和时间的方便方法。如果您还没有使用过,可以尝试其中一个,例如moment.js

使用moment.js实现自定义适配器看起来像这样。

创建CustomDateAdapter.ts并像这样实现:

import { NativeDateAdapter } from "@angular/material";
import * as moment from 'moment';

export class CustomDateAdapter extends NativeDateAdapter {
    format(date: Date, displayFormat: Object): string {
        moment.locale('ru-RU'); // Choose the locale
        var formatString = (displayFormat === 'input')? 'DD.MM.YYYY' : 'LLL';
        return moment(date).format(formatString);
    }
}

在你的app.module.ts文件中:

import { DateAdapter } from '@angular/material';

providers: [
    ...
    {
        provide: DateAdapter, useClass: CustomDateAdapter
    },
    ...
]

就是这样。简单易行,无需重新发明轮子。


4

创建一个日期格式的常量。

export const DateFormat = {
parse: {
  dateInput: 'input',
  },
  display: {
  dateInput: 'DD-MMM-YYYY',
  monthYearLabel: 'MMMM YYYY',
  dateA11yLabel: 'MM/DD/YYYY',
  monthYearA11yLabel: 'MMMM YYYY',
  }
};

在应用程序模块中使用以下代码

 providers: [
  { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] },
  { provide: MAT_DATE_FORMATS, useValue: DateFormat }
]

这个可以工作,但似乎与formControl验证发生了冲突。虽然我还没有深入研究它。 - Josh Leslie

3

为什么不要使用Angular的DatePipe?

import {Component} from '@angular/core';
import {DateAdapter, MAT_DATE_FORMATS, NativeDateAdapter} from '@angular/material';
import {FormControl} from '@angular/forms';
import {DatePipe} from '@angular/common';

export const PICK_FORMATS = {
    parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}},
    display: {
        dateInput: 'input',
        monthYearLabel: {year: 'numeric', month: 'short'},
        dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
        monthYearA11yLabel: {year: 'numeric', month: 'long'}
    }
};
class PickDateAdapter extends NativeDateAdapter {
    format(date: Date, displayFormat: Object): string {
        if (displayFormat === 'input') {
            return new DatePipe('en-US').transform(date, 'EEE, MMM dd, yyyy');
        } else {
            return date.toDateString();
        }
    }
}
@Component({
    selector: 'custom-date',
    template: `<mat-form-field>
                   <input matInput [formControl]="date" />
                   <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
                   <mat-datepicker #picker></mat-datepicker>
               </mat-form-field>`,
    providers: [
        {provide: DateAdapter, useClass: PickDateAdapter},
        {provide: MAT_DATE_FORMATS, useValue: PICK_FORMATS}
    ]
})
export class DateComponent {
    date = new FormControl(new Date());
    constructor() {}
}

3

Robouste工作得非常好!!

我制作了一个简单的(Angular 4 "@angular/material": "^2.0.0-beta.10"),首先创建了datepicker.module.ts文件。



    import { NgModule }  from '@angular/core';
    import { MdDatepickerModule, MdNativeDateModule, NativeDateAdapter, DateAdapter, MD_DATE_FORMATS  }  from '@angular/material';

    class AppDateAdapter extends NativeDateAdapter {
        format(date: Date, displayFormat: Object): string {
            if (displayFormat === 'input') {
                const day = date.getDate();
                const month = date.getMonth() + 1;
                const year = date.getFullYear();
                return `${year}-${month}-${day}`;
            } else {
                return date.toDateString();
            }
        }
    }

    const APP_DATE_FORMATS = {
    parse: {
    dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
    },
    display: {
    // dateInput: { month: 'short', year: 'numeric', day: 'numeric' },
    dateInput: 'input',
    monthYearLabel: {year: 'numeric', month: 'short'},
    dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
    monthYearA11yLabel: {year: 'numeric', month: 'long'},
    }
    };

    @NgModule({
    declarations:  [ ],
    imports:  [ ],
        exports:  [ MdDatepickerModule, MdNativeDateModule ],
    providers: [
    {
        provide: DateAdapter, useClass: AppDateAdapter
    },
    {
        provide: MD_DATE_FORMATS, useValue: APP_DATE_FORMATS
    }
    ]
    })

    export class DatePickerModule {

    }

只需导入它(app.module.ts)即可。


    import {Component, NgModule, VERSION,  ReflectiveInjector}   from '@angular/core'//NgZone,
    import { CommonModule }              from '@angular/common';
    import {BrowserModule}               from '@angular/platform-browser'
    import { BrowserAnimationsModule }        from '@angular/platform-browser/animations';
    import { FormsModule }              from '@angular/forms';
    import { DatePickerModule }            from './modules/date.picker/datepicker.module';

    @Component({
    selector: 'app-root',
    template: `
    <input (click)="picker.open()" [mdDatepicker]="picker" placeholder="Choose a date" [(ngModel)]="datepicker.SearchDate"  >
    <md-datepicker-toggle mdSuffix [for]="picker"></md-datepicker-toggle>
    <md-datepicker #picker touchUi="true"  ></md-datepicker>
    `,
    })


    export class App{
        datepicker = {SearchDate:new Date()}
        constructor( ) {}

        }

    @NgModule({
    declarations: [ App ],
    imports: [ CommonModule, BrowserModule, BrowserAnimationsModule, FormsModule, DatePickerModule],
    bootstrap: [ App ],
    providers: [   ]//NgZone
    })
    export class AppModule {}


2

根据Arthur z和Gil Epshtain的原始想法,我将moment更改为date-fns。在angular @angular/material": "^10.0.2中进行了测试。

创建CustomDateAdapter.ts并按照以下方式实现:

import { NativeDateAdapter } from "@angular/material/core";
import { format } from 'date-fns';
import { es } from 'date-fns/locale'

export class CustomDateAdapter extends NativeDateAdapter {
    format(date: Date, displayFormat: Object): string {
        var formatString = (displayFormat === 'input')? 'DD.MM.YYYY' : 'dd-MM-yyyy';
        return format(date, formatString, {locale: es});
    }
}

在你的 app.module.ts 文件中:
import { DateAdapter } from '@angular/material';

providers: [
    ...
    {
        provide: DateAdapter, useClass: CustomDateAdapter
    },
    ...
]

1

我使用了@igor-janković提供的解决方案,但出现了“错误:未捕获(在承诺中):TypeError:无法读取未定义的属性'dateInput'”的问题。我意识到这个问题是因为MY_DATE_FORMATS需要像type MdDateFormats一样声明:

export declare type MdDateFormats = {
    parse: {
        dateInput: any;
    };
    display: {
        dateInput: any;
        monthYearLabel: any;
        dateA11yLabel: any;
        monthYearA11yLabel: any;
    };
};

因此,正确声明MY_DATE_FORMATS的方式是:
const MY_DATE_FORMATS:MdDateFormats = {
   parse: {
       dateInput: {month: 'short', year: 'numeric', day: 'numeric'}
   },
   display: {
       dateInput: 'input',
       monthYearLabel: {year: 'numeric', month: 'short'},
       dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
       monthYearA11yLabel: {year: 'numeric', month: 'long'},
   }
};

通过以上修改,该解决方案对我有效。

祝好


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接