Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change output format of material 2 date-picker

I am using angular material 2 Date-Picker component

The only string input it understands is in ISO date format

Ex. "2017-11-13T10:39:28.300Z"

But i want to patch my form control with locale date value

Ex. "11/13/2017, 4:09:46 PM"

So that it output the later format and even expects this format.

How can i do this? Is there a way to not use ISO but custom formats?

Some Thoughts:

Should i write customDateAdaptor?

Update:

https://stackblitz.com/edit/angular-material-moment-adapter-example-bqvm2f

i have tried to implement custom dateAdaptor by extending nativeDateAdaptor

like image 256
Ankit Raonka Avatar asked Nov 13 '17 10:11

Ankit Raonka


3 Answers

The best solution would be to use ControlValueAccessor and make a custom input component, this will have you in control of input and output of the component.

update:

Here is the reference implementation using this approach reproduced by Moutaz-homsi

https://stackblitz.com/edit/angular-dlxnmx?file=app%2Fcva-date.component.ts

like image 157
Ankit Raonka Avatar answered Oct 02 '22 21:10

Ankit Raonka


You need to create a class extending NativeDateAdapter (from "@angular/material/core")

If you override the format function you will change the way the date is displayed on the input after selecting a date. The parse function is called when you edit the input value manually, to display a valid date.

See the 2nd comment for more details: https://github.com/angular/material2/issues/5722

EDIT:

I couldn't find a way to format the output so I've wrapped the material datepicker component to a custom component.

This custom component has a 2 way binding on a property to get the date: @Input() selectedValue and @Output() selectedValueChange: EventEmitter<any> = new EventEmitter<any>();

A private _selectedValue; is set on ngInit, it will contain the datepicker date.

Then in the template, the html datepicker input element has [(ngModel)]="_selectedValue" (dateChange)="onChange($event)"

The onChange function gets the datepicker value _selectedValue, formats it and emit it to selectedValueChange.

The final component looks like this:

import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
import {
  DateAdapter,
  NativeDateAdapter,
  MAT_DATE_FORMATS,
  MAT_DATE_LOCALE
} from "@angular/material/core";
import * as moment from "moment";

const CUSTOM_DATE_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" }
  }
};
const dateFormat = "YYYY-MM-DD";
// date adapter formatting material2 datepickers label when a date is selected
class AppDateAdapter extends NativeDateAdapter {
  format(date: Date, displayFormat: Object): string {
    if (displayFormat === "input") {
      return moment(date).format(dateFormat);
    } else {
      return date.toDateString();
    }
  }
}
@Component({
  selector: "datepicker",
  templateUrl: "./datepicker.component.html",
  styleUrls: ["./datepicker.component.scss"],
  providers: [
    { provide: MAT_DATE_FORMATS, useValue: CUSTOM_DATE_FORMATS },
    { provide: DateAdapter, useClass: AppDateAdapter }
  ]
})
export class DatepickerComponent implements OnInit {
  @Input() placeholder;
  @Output() onFilter: EventEmitter<any> = new EventEmitter<any>();
  @Input() selectedValue;
  @Output() selectedValueChange: EventEmitter<any> = new EventEmitter<any>();

  private _selectedValue;
  constructor() {}

  ngOnInit() {
    this._selectedValue = this.selectedValue;
  }

  onChange($event) {
    this.selectedValue = this.updateDate($event.value);
    this.onFilter.emit(this.selectedValue);
  }

  updateDate(date) {
    let formatedDate;
    if (date !== undefined) {
      formatedDate = moment(date).format(dateFormat);
    }
    this.selectedValueChange.emit(formatedDate);
    return formatedDate;
  }
}
like image 41
remborg Avatar answered Oct 02 '22 22:10

remborg


Not sure, if you are already doing this but I found some information that might give you some idea on your implementation.

As of today the Angular Material Date Module supports two ways of providing a date value MatNativeDateModule and MatMomentDateModule. The MatNativeDateModule accepts ISO 8601 format by default. But since you don't want to use ISO format, I would suggest using MatMomentDateModule (Moment.js implementation).

When we use the MatMomentDateModule the date object is not anymore a JavaScript Date object but instead is a Moment.js instance(take advantage of methods available to a Moment js instance like format()). There are basic to intermediate examples available on Material Date Picker docs page using the Moment.js. Also, once your date is a Moment.js instance, you could overwrite the methods(format, parse.) from MomentDateAdapter instead of native date adapter.

like image 29
mrsan22 Avatar answered Oct 02 '22 23:10

mrsan22