How to change output format of material 2 date-picker
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
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;
}
}
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.