1

It is possible to change date format by button? For example, the default format is DD/MM/YYYY, but when i'm click the button i would register new format, for example YYYY/MM/DD it is possible ? Im started with that code:

part of ts file

const moment = _rollupMoment || _moment;
export const MY_FORMATS = {
    parse: {
        dateInput: 'DD/MM/YYYY',
    },
    display: {
        dateInput: 'DD/MM/YYYY',
        monthYearLabel: 'MM YYYY',
        dateA11yLabel: 'DD/MM/YYYY',
        monthYearA11yLabel: 'MM YYYY',
    },
};


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



changeFormat() {
    ????????
}

html file:

   <input matInput [matDatepicker]="picker" placeholder="mm.dd.yyyy"
                      (click)="picker.open()" #birthInput>
               <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
               <mat-datepicker #picker></mat-datepicker>
 <span (click)="changeFormat()"></span>

Thanks for any help.

Czachovsky
  • 157
  • 2
  • 7

2 Answers2

5

You're defining a fixed MY_FORMAT, but you can define a class like

export class MyFormat{
  value=1;
  constructor(){}
  get display(){
    return this.value==1?
     {
        dateInput: 'LL',
        monthYearLabel: 'MMM YYYY',
        dateA11yLabel: 'LL',
        monthYearA11yLabel: 'MMMM YYYY',
      }:{
        dateInput: 'DD/MM/YYYY',
        monthYearLabel: 'MM YYYY',
        dateA11yLabel: 'DD/MM/YYYY',
        monthYearA11yLabel: 'MM YYYY',
    }
  }
  get parse(){
    return this.value==1?{
        dateInput: 'LL',
      }:{
      dateInput: 'DD/MM/YYYY'
      }
  }
  
}

Then in provider you use this class

  providers: [
    {provide: MAT_DATE_FORMATS, useClass: MyFormat},
  ],

Finally, you inject in contructor of your component the provider to access to the variable "value"

  constructor(@Inject(MAT_DATE_FORMATS) public config: MyFormat){}

Well, you need, when change the format "redraw" the dateForm, e.g.

  change(){
    this.config.value=this.config.value==1?2:1 //we change the "value"
    this.date=new FormControl(this.date.value)  //give the value
  }

But, be carefully, you need use a CustomDateAdapter or use the MomentDateAdapter

Using a MomentDateAdapter it's import in the module MomentDateModule

@NgModule({
  imports: [
    ...
    MomentDateModule,
  ],

If you want to use a CustomDateAdapter you can use some like

export class CustomDateAdapter extends NativeDateAdapter {

  formato="YYY/MM/DD"
  parse(value: any) {
    const parts = value.match(/\d{1,4}/g);
    if (parts && parts.length == 3) {
      const order = this.formato.match(/Y{2,4}|M{1,2}|D{1,2}/g);
      if (order) {
        const year = +parts[
          order.indexOf("YYYY") < 0
            ? order.indexOf("YY")
            : order.indexOf("YYYY")
        ];
        const month = +parts[
          order.indexOf("MM") < 0 ? order.indexOf("M") : order.indexOf("MM")
        ];
        const day = +parts[
          order.indexOf("DD") < 0 ? order.indexOf("D") : order.indexOf("DD")
        ];
        return new Date(year<100?year+2000:year, month - 1, day);
      }
    }
    return null;
  }
  format(date: any, displayFormat: any): string {
    if (displayFormat=="MMM YYYY")
      return this.getMonthNames('long')[date.getMonth()]+' '+date.getFullYear()

    const result= displayFormat
      .replace("YYYY", date.getFullYear())
      .replace("YY", date.getYear())
      .replace("MMM", this.getMonthNames('long')[date.getMonth()])
      .replace("MM", ("00" + (date.getMonth() + 1)).slice(-2))
      .replace("M", date.getMonth() + 1)
      .replace("DD", ("00" + date.getDate()).slice(-2))
      .replace("M", date.getDate())
      return result;
  }
}

And you inject in constructor the adapter adn cahnge the "formato" value

constructor(@Inject(MAT_DATE_FORMATS) private config: MyFormat,
            @Inject(DateAdapter) private customDateAdapter:CustomDateAdapter) {
    this.config.value = 1;
    this.customDateAdapter.formato='YYYY/MM/DD'
  }

  change() {
    this.config.value = this.config.value == 1 ? 2 : 1;
    this.customDateAdapter.formato=this.config.value==1?'DD/MM/YYYY' : 'YYYY/MM/DD';
    this.date = new FormControl(this.date.value);
  }

You can see a stackblitz using MomentAdapter

You can see a stackblitz using CustomDateAdapter

Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • This is really great. I was able to inject `@Inject(LOCALE_ID) public locale: string` and use `this.locale` in a switch to do different date parsing by culture. I'm using Luxon, but the built-in "localized" formats aren't flexible/comprehensive enough. The only downside seems to be I have to inject it in every component where I use a datepicker instead of just once in the module/app, but I can live with that. – Roobot Aug 18 '21 at 22:15
1

You can use a current workaround for this.

please check this example https://stackblitz.com/edit/angular-mat-datepicker-xrwgmu?file=app/datepicker-overview-example/datepicker-overview-example.component.ts

<mat-form-field class="mt-2">
    <input
          matInput
          placeholder="Date"
          (focus)="datePicker.open();"
          [value]="dateInput.value | date:format">
    <input
          #dateInput
          class="hidden-dateinput"
          [matDatepicker]="datePicker">
    <mat-datepicker-toggle matSuffix [for]="datePicker"></mat-datepicker-toggle>
    <mat-datepicker #datePicker></mat-datepicker>
</mat-form-field>

and this is in style.css

.hidden-dateinput {
  opacity: 0;
  position: absolute;
  width: 1px;
  height: 1px;
}

and the format can be changed dynamically

Ashot Aleqsanyan
  • 4,252
  • 1
  • 15
  • 27