Angular-material: Create a separate format for each date picker on the same page
As I know in angular-material official, they showed you how to configure the format applies to all date-picker in the whole application or component level. But in the real case, we need to apply a separate format to each date-picker instead of only at the component.
So, I will show you how to customize it(or you can go to the demo to see how it works)
Firstly, I will create a class CustomDateFormat
at file ./custom-date-format.ts
to process the parse
and desiplay
format as bellow:
export interface DateParse { dateInput: string; }
export type DateDisplay = DateParse & {
monthYearLabel?: string,
dateA11yLabel?: string,
monthYearA11yLabel?: string,
};
export class CustomDateFormat {
private _parse: DateParse = {
dateInput: 'YYYY/MM/DD'
};
private _display: DateDisplay = {
dateInput: 'YYYY/MM/DD',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMM YYYY'
};
set parse(parse: DateParse) {
this._parse = Object.assign({}, this._parse, parse);
}
get parse(): DateParse {
return this._parse;
}
set display(display: DateDisplay) {
this._display = Object.assign({}, this._display, display);
}
get display(): DateDisplay {
return this._display;
}
updateDateFormat(parse: DateParse, display?: DateDisplay) {
this.parse = parse;
if (!display) {
display = parse;
}
this.display = display;
}
}
As you can see the format above I have used @angular/material-moment-adapter
. So, don’t forget to npm install @ngular/material-moment-adapter --save
into your app.
Secondly, we create a directive to manipulate the MAT_DATE_FORMATS
import {Directive, Inject, Input, Optional} from '@angular/core';
import {NgControl} from '@angular/forms';
import {DateAdapter, MAT_DATE_FORMATS} from '@angular/material/core';
import {CustomDateFormat, DateDisplay, DateParse} from './custom-date-format';
import {MomentDateAdapter} from '@angular/material-moment-adapter';
@Directive({
selector: '[datePickerFormat]',
providers: [
{
provide: DateAdapter,
useClass: MomentDateAdapter
},
{
provide: MAT_DATE_FORMATS,
useClass: CustomDateFormat
}
]
})
export class DatePickerFormatDirective {
@Input() public configDateParse: DateParse;
@Input() public configDateDisplay: DateDisplay;
@Input('datePickerFormat')
set datePickerFormat(format: string) {
if (this.configDateParse) {
this.matDateFormat.updateDateFormat(
this.configDateParse,
this.configDateDisplay
);
} else {
this.matDateFormat.updateDateFormat({dateInput: format});
} // We need this for the first time to tell component change new format
const value = this.ngControl.value;
this.ngControl.valueAccessor?.writeValue(value);
}
constructor(
@Inject(MAT_DATE_FORMATS) public matDateFormat: CustomDateFormat,
@Optional() private ngControl: NgControl
) {
}
}
Thirdly, inject DatePickerFormatDirective
to theAppModule
like this
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { MaterialModule } from "./material.module";
import { MatDatepickerModule } from "@angular/material/datepicker";
import { MatMomentDateModule } from "@angular/material-moment-adapter";
import { AppComponent } from "./app.component";
import { DatePickerFormatDirective } from "./date-picker-format.directive";
@NgModule({
declarations: [AppComponent, DatePickerFormatDirective],
imports: [
BrowserModule,
BrowserAnimationsModule,
MaterialModule,
FormsModule,
ReactiveFormsModule,
MatDatepickerModule,
MatMomentDateModule
],
bootstrap: [AppComponent]
})
export class AppModule {}
Finally, here are the use cases
At app.component.ts
we define the form with data is new Date()
at the FormControl
import {Component, ViewEncapsulation} from '@angular/core';
import {FormBuilder, FormControl, FormGroup} from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
format1: new FormControl(new Date()),
format2: new FormControl(new Date())
});
}
onSubmit() {
console.log(this.form.value);
}
}
And in template app.component.html
<div class="container">
<div class="segment">
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="block">
<mat-form-field>
<mat-label>Date Picker (format: YYYY/MM/DD)</mat-label>
<input
matInput
[matDatepicker]="datepicker"
datePickerFormat="YYYY/MM/DD"
formControlName="format1"
>
<mat-datepicker-toggle matSuffix [for]="datepicker"></mat-datepicker-toggle>
<mat-datepicker #datepicker></mat-datepicker>
</mat-form-field>
</div>
<div class="block">
<mat-form-field>
<mat-label>Date Picker (format: MMMM Do YYYY)</mat-label>
<input
matInput
[matDatepicker]="matDatepicker"
datePickerFormat="MMMM Do YYYY"
formControlName="format2"
>
<mat-datepicker-toggle matSuffix [for]="matDatepicker"></mat-datepicker-toggle>
<mat-datepicker #matDatepicker></mat-datepicker>
</mat-form-field>
</div>
<div class="block">
<button mat-raised-button color="accent" type="submit">
Submit
</button>
</div>
</form>
</div>
</div>
You can see the demo
That’s all.
Thank you for reading.