I have 3 date picker fields, contractPeriodFrom, contractPeriodTo and dateOfAppointment. The dateOfAppointment should be between the contractPeriodFrom and contractPeriodTo. I am unsure how to do this as both contractPeriod fields are form controls.
<div fxLayout="row">
<mat-form-field fxFlex="50">
<input matInput [matDatepicker]="picker2" formControlName="contractPeriodFrom" readonly>
<mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
<mat-form-field fxFlex="50">
<input matInput [matDatepicker]="picker3" formControlName="contractPeriodTo" readonly>
<mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle>
<mat-datepicker #picker3></mat-datepicker>
</mat-form-field>
</div>
<div fxLayout="row" class="mt-16">
<mat-form-field fxFlex="50">
<input matInput [matDatepicker]="picker1" formControlName="dateOfAppointment" readonly>
<mat-datepicker-toggle matSuffix [for]="picker1"></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker>
</mat-form-field>
</div>
The form fields are part of a form group and initialized as below -
this.lieUpdateForm = this._formBuilder.group({
dateOfAppointment: [this.selectedLIE.dateOfAppointment || ''],
contractPeriodFrom: [this.selectedLIE.contractPeriodFrom || ''],
contractPeriodTo: [this.selectedLIE.contractPeriodTo || ''],
});
Have a look here https://material.angular.io/components/datepicker/overview#date-validation. There are two solutions min/max
or matDatepickerFilter
. I would suggest you to use the matDatepickerFilter
one, being cleaner , more flexible and not requiring subscriptions to valueChanges
.
matDatepickerFilter
Add the [matDatepickerFilter]
binding to the input:
<input matInput
[matDatepicker]="picker1"
formControlName="dateOfAppointment" readonly
[matDatepickerFilter]="dateFilter"
>
Then add a validation function to your component (note that is a lambda and not a member function, read more here MatDatepickerFilter - Filter function can't access class variable)
public dateFilter = (d: Date): boolean => {
const value = this.lieUpdateForm.value;
return (d >= this.toDate(value.contractPeriodFrom)) && (d <= this.toDate(value.contractPeriodTo));
}
min/max
Add the [min]
and [max]
binding to the input:
<input matInput
[matDatepicker]="picker1"
formControlName="dateOfAppointment" readonly
[min]="minDate" [max]="maxDate"
>
Then after right after assigning lieUpdateForm
add:
this._subscription = this.lieUpdateForm
.valueChanges.subscribe(value => {
this.minDate = toDate(value.contractPeriodFrom);
this.maxDate = toDate(value.contractPeriodTo);
});
Do not forget to clear _subscription
onDestroy
toDate
toDate
is a function that makes sure we are dealing with Date objects. According to the documentation it should work just fine without it. I added it just in case. This is the implementation if needed:
protected toDate(d: Date | string): Date {
return (typeof d === 'string') ? new Date(d) : d;
}