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
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.
You probably need to write a completely new adapter or use the moment adapter. @angular/material-moment-adapter:5.0.0-rc0
. The moment adapter uses momentjs and allows you much more control on the output format.
Moment is also able to parse different input formats.
The NativeDateAdapter
uses the Intl API to format the output date. You can try to provide a custom MAT_NATIVE_DATE_FORMATS instance but I am not sure how far this gets you.
EDIT
You are currently using 2.0.0-beta12 of angular/material, that doesn't fit with your code based on 5.0.0-rc0/master. There are changes in the codebase, especially the deserialize function which is not present in 2.0.0-beta12, that's why it is not being called. If you can't update to angular 5 then look at MatDatepickerInput.setValue/coerceDateProperty
which sets the date into your FormControl
.
you can call Emitter of this module (for example click event) and change model binded to this module to secondary model.
First import moment and set format .
https://momentjs.com/
import * as moment from 'moment';
setDateFormat(date) {
this.myDate = moment(date).format('YYYY/MM/DD HH:mm:ss');
}
you can change it's format like this:
const Date = Date.replace(/-/g, '/')