【问题标题】:How to change Angular Material Datepicker format in run-time如何在运行时更改 Angular Material Datepicker 格式
【发布时间】:2018-08-01 13:34:37
【问题描述】:

我正在开发一个具有 Material 设计的 Angular 应用程序,并且我正在使用 Moment.js 来解析和格式化日期。

在我的一个页面中,我有一个Material's Datepicker。我已按照材料的指南使 Datepicker 与 moment 对象一起工作 - 而不是在本机 Date 对象上工作。

我还设法以某种格式在 Datepicker 中显示日期。但是这种格式在组件的提供程序中是硬编码的。 如何在运行时根据用户偏好更改格式?

这是我目前所拥有的:

我已经安装了 npm 的包:

$ npm i moment -S
$ npm i @angular/material-moment-adapter -S
// app.module.ts
import { MatMomentDateModule } from '@angular/material-moment-adapter'
...
@NgModule({
  imports: [
    MatMomentDateModule,
...
// demo.component.ts
import * as moment from 'moment';
import { MAT_DATE_FORMATS } from '@angular/material/core';
const MY_FORMATS = {
  parse: {
    dateInput: 'LL',
  },
  display: {
    dateInput: 'LL',
    monthYearLabel: 'MMM YYYY',
    dateA11yLabel: 'LL',
    monthYearA11yLabel: 'MMMM YYYY',
  },
};
@Component({
  selector: 'app-demo',
  templateUrl: './demo.component.html',
  styleUrls: ['./demo.component.scss'],
  providers: [
    { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
  ],
})
export class DemoComponent {
   public dateVal = moment();
}
// demo.component.html
<mat-form-field>
  <input matInput [matDatepicker]="myDatePicker" [(ngModel)]="dateVal">
  <mat-datepicker-toggle matSuffix [for]="myDatePicker"></mat-datepicker-toggle>
  <mat-datepicker #myDatePicker></mat-datepicker>
</mat-form-field>

如您所见,日期格式是在组件的提供程序中定义的。如何在运行时更改它?

可以在此处找到一个工作示例:
https://stackblitz.com/angular/mgaargebgpd?file=app%2Fdatepicker-formats-example.ts

【问题讨论】:

    标签: angular datepicker angular-material momentjs


    【解决方案1】:

    好的,所以我终于找到了在运行时更改mat-date-picker 格式的方法(文档根本没有帮助)。

    第 1 步 - 创建一个提供格式的服务。

    您可能已经有这样的服务,如果没有,您应该创建一个,这样您就可以在一个地方控制日期格式。

    // date-time.service
    import { Injectable } from '@angular/core';
    import * as moment from 'moment';
    
    @Injectable({ providedIn: 'root' })
    export class DateTimeService
    {
      public getFormat(): string
      {
        return "DD-MM-YYYY"; // add you own logic here
      }
      public getLocale(): string
      {
        return "he-IL"; // add you own logic here
      }  
    }
    

    步骤 #2 - 创建一个 CustomDateAdapter,它将负责在运行时解析日期

    // customDateAdapter.ts
    import { Injectable } from '@angular/core';
    import { MomentDateAdapter } from '@angular/material-moment-adapter';
    import * as moment from 'moment';
    import { DateTimeService } from './date-time.service';
    
    @Injectable()
    export class CustomDateAdapter extends MomentDateAdapter
    {
      constructor(private _dateTimeService: DateTimeService)
      {
        super('en-US'); // set default locale
      }
    
      public format(date: moment.Moment, displayFormat: string): string
      {
        const locale = this._dateTimeService.getLocale();
        const format = this._dateTimeService.getFormat();
    
        return date.locale(locale).format(format);
      }
    }
    

    请注意:“CustomDateAdapter”是一个常规类,而不是一个组件。尽管我们正在向此类注入服务。为此,我们需要将@Injectable() 装饰器添加到“CustomDateAdapter”,并在app.module.ts 中进行一些轻微的更改。

    步骤 #3 - 修改 app.module.ts 以支持自定义格式并允许对 CustomDateAdapter 的依赖注入。

    // app.module.ts
    import { DateAdapter, MatNativeDateModule } from '@angular/material';
    import { MatMomentDateModule } from '@angular/material-moment-adapter'
    import { CustomDateAdapter } from './<some-path>/customDateAdapter';
    
    @NgModule({
      imports:
      [
        MatNativeDateModule,
        MatMomentDateModule
      ],
      providers:
      [
        CustomDateAdapter, // so we could inject services to 'CustomDateAdapter'
        { provide: DateAdapter, useClass: CustomDateAdapter }, // Parse MatDatePicker Format
      ]
    })
    export class AppModule { /* ... */ }
    

    附言
    请注意,问题中的代码(来自“demo.component.ts”)不再相关。

    Demo at Stackblitz

    【讨论】:

    • 你能创建一个 stackblitz 演示吗?
    • 如果我在 2 个不同的页面中需要两种不同的格式,这将不起作用。
    • 这真的很有帮助!
    • 使用此方法也会更改标题中的显示值,因此它不会显示当月的“Feb 2021”,而是以您在此处提供的任何格式显示所选日期。这对于您的用例可能是可以接受的,只是想指出这一点。
    • 格式仅在选定日期后更改。如何让它立即改变?
    【解决方案2】:

    感谢您的想法!只是为了澄清。您可以使用非单例服务来设置日期选择器值的自定义格式。扩展您的代码:

    import { Injectable } from '@angular/core';
        @Injectable({ providedIn: 'root' })
        export class DateTimeService {
            private _format = 'DD.MM.YYYY';
    
            set format(value: string) {
                this._format = value;
            }
    
            public getFormat(): string {
                return this._format;
            }
    
            public getLocale(): string {
                return 'ru-ru';
            }
        }
    

    如果你像这样注入这个服务:

    providers: [
            { provide: MAT_DATE_LOCALE, useValue: 'ru-ru' },
            CustomDateAdapter,
            DateTimeService,
            { provide: DateAdapter, useClass: CustomDateAdapter, deps: [DateTimeService] }
    ]
    

    您可以在组件工作期间存储组件中的任何值。

    constructor(private dateTimeService: DateTimeService) {
        }
    
        ngOnInit() {
            this.dateTimeService.format = this.format;
        }
    

    【讨论】:

      【解决方案3】:

      更新:如果用户想要手动输入 DateTime 而不是从 DateTime 选择器中选择 DateTime(删除输入 DateTime 上的只读属性),@Gil Epshtain 的解决方案将不起作用。 我对customDateAdapter.ts的更新:

      public parse(value: any, parseFormat: string | string[]): moment.Moment | null {
      if(!value) {
        return null
      }
      const format = this._dateTimeService.getFormat();
      return _moment(value, format, false);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-28
        • 1970-01-01
        • 2015-12-10
        • 2021-07-08
        • 2021-02-23
        • 2020-01-27
        相关资源
        最近更新 更多