endDate > startDate in angular material

john picture john · Nov 21, 2017 · Viewed 10.8k times · Source

I am building a component (html, css, spec.ts, ts) in angular in which I always want endDate > startDate. I have followed this link https://material.angular.io/components/datepicker/overview in order make multiple datepickers.

This is the html which I have used for startDate and endDate.

startDate:

<div class="item item-1" fxFlex="50%" fxFlexOrder="1">
   <mat-form-field>
      <input matInput [matDatepicker]="picker1" placeholder="{{'PORTAL.STARTDATE' | translate}}" type="text" formControlName="startDate" [(ngModel)]="unavailability.startDate" [readonly]="!componentPermission.writePermission">
      <mat-datepicker-toggle matSuffix [for]="picker1"></mat-datepicker-toggle>
      <mat-datepicker #picker1></mat-datepicker>
   </mat-form-field>
</div>

endDate:

<div class="item item-2" fxFlex="50%" fxFlexOrder="2">
   <mat-form-field>
      <input matInput [matDatepicker]="picker2" placeholder="{{'PORTAL.ENDDATE' | translate}}" type="text" formControlName="endDate" [(ngModel)]="unavailability.endDate" [readonly]="!componentPermission.writePermission">
      <mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
      <mat-datepicker #picker2></mat-datepicker>
   </mat-form-field>
</div>

The validateForm() code which I have used in the ts is:

  validateForm() {
    this.unavailabilityForm = this.formBuilder.group({
      'startDate': [''],
      'endDate': ['']

    });
  } 

I am pretty sure I have to make some changes in the validateForm() code but I am not sure what changes I have to make.

Answer

AJT82 picture AJT82 · Nov 22, 2017

Since you seem to be going with a mix of reactive form and template driven, I would choose a reactive form completely. Implementing Validation is also in my opinion easier and cleaner. This also then means, you can drop ngModel altogether, which I would then strongly suggest, since it can cause unexpected issues to have two bindings (form control and ngModel). EDIT 2/2019: ngModel together with reactive forms are now also luckily not allowed since v7. That is in my opinion good, since it was misused way too much!

So build your form and attach a custom validator. In case you have a large form, I would attach the custom validator to a nested group of your dates, as it sits in this example, the validator is firing whenever there is any change in the form, doesn't matter if it's the date fields, or some other field.

constructor(private formBuilder: FormBuilder) { 
  this.unavailabilityForm = this.formBuilder.group({
    startDate: [''],
    endDate: ['']
  }, {validator: this.checkDates});  
}

If you are getting your values for variable unavailability at a later stage, you can use patchValue or setValue to assign the values to your form controls:

this.unavailabilityForm.setValue({
  startDate: this.unavailability.startDate;
  endDate: this.unavailability.endDate;
})

The custom validator simply checks that the end date is a later date than the startdate and returns null if it is valid, or then a custom validation error:

checkDates(group: FormGroup) {
  if(group.controls.endDate.value < group.controls.startDate.value) {
    return { notValid:true }
  }
  return null;
}

and then you can display this custom error in template with:

<small *ngIf="unavailabilityForm.hasError('notValid')">Not valid</small>

Also remember to mark this formgroup in your form tag:

<form [formGroup]="unavailabilityForm">