简体   繁体   中英

How do I set Min and Max values on a Datepicker field based on two other Datepicker fields - Angular Material

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;
}
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="picker" placeholder="Choose a date">

Then you can set the Value for maxDate and minDate in ts file

this.lieUpdateForm.get("dateOfAppointment").valueChanges.subscribe(selectedValue => {
  console.log('dateOfAppointment value changed')
  console.log(selectedValue)                              //latest value of dateOfAppointment
  console.log(this.lieUpdateForm.get("dateOfAppointment").value)   //latest value of dateOfAppointment
})

The accepted answer has one flaw though, when using matDateFilter the performance is affected badly. I know the logic in filterFunction is written in such as way that it must be executed minimum times but what if first date isn't provided and user want to make year disabled when false is returned looks like it recursively check for internal dates as well which makes it to get executed lots of times

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM