How to change Angular Material Datepicker format in run-time

前端 未结 3 1851
醉话见心
醉话见心 2021-02-01 10:08

I\'m working on an Angular App with Material Design, and I\'m using Moment.js to parse and format dates.

In one of my p

相关标签:
3条回答
  • 2021-02-01 10:25

    OK, so I finally find a way to change the mat-date-picker format during run-time (the documentation didn't help at all).

    Step #1 - Create a service that will provide the formatting.

    You probable already have a service like this, if no you should create one, so you could control the date-formatting in one place.

    // 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
      }  
    }
    

    Step #2 - Create a CustomDateAdapter, that will be responsible for parsing the date during run-time

    // 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);
      }
    }
    

    Please Notice: That "CustomDateAdapter" is a regular class, and not a component. Although we are injecting a service to this class. To achieve this we need to add the @Injectable() decorator to the "CustomDateAdapter", and make some light changes in the app.module.ts.

    Step #3 - Modify the app.module.ts to support custom formating and to allow Dependence Injection to 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 { /* ... */ }
    

    P.S
    Please notice that the code from the question (from the "demo.component.ts") isn't relevant any more.

    Demo at Stackblitz

    0 讨论(0)
  • 2021-02-01 10:34

    Thanks for your idea! Just for clarification. You can use non-singleton service for setting custom formatting of datepicker value. Extending your code:

    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';
            }
        }
    

    If you inject this service like this:

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

    you can store any value from your component during component working.

    constructor(private dateTimeService: DateTimeService) {
        }
    
        ngOnInit() {
            this.dateTimeService.format = this.format;
        }
    
    0 讨论(0)
  • 2021-02-01 10:42

    update: @Gil Epshtain's solution doesn't work if the user wants to manually input DateTime instead of pick DateTime from DateTime picker (remove read-only attribute on input DateTime). my update on 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);
    }
    
    0 讨论(0)
提交回复
热议问题