Angular Material Datepicker Validation

By Arvind Rai, July 20, 2020
This page will walk through Angular Material Datepicker validation example. Datepicker can be validated in following ways.
1. Validate required using Validators.required in FormControl.
2. For minimum and maximum date selection, use min and max property of Datepicker input text.
3. We can use matDatepickerFilter to validate Datepicker conditionally.
4. We can create custom validator to validate Datepicker.
5. For Datepicker range selection, use matStartDateInvalid and matEndDateInvalid error.

On this page we will provide complete demo to validate Datepicker step-by-step.

Technologies Used

Find the technologies being used in our example.
1. Angular 10.0.0
2. Angular Material 10.0.0
3. Node.js 12.5.0
4. NPM 6.9.0
5. moment.js 2.27.0

Required Validation

For required validation, configure Validators.required in form control.
studentForm = this.formBuilder.group({
  dateOfBirth: ['', Validators.required],
  ------
}); 
Find the HTML template for Datepicker. Here we are writing error message using <mat-error>. The error message will be displayed if required validation fails.
<mat-form-field>
  <mat-label>Date of Birth</mat-label>
  <input matInput [matDatepicker]="dob" formControlName="dateOfBirth">
  <mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
  <mat-datepicker #dob></mat-datepicker>

  <mat-error *ngIf="studentForm.get('dateOfBirth').hasError('required')">
     Valid date required.
  </mat-error>    
</mat-form-field> 

min and max Validation

To validate minimum and maximum date entered by user manually or selected from calendar, can be validated using min and max property. It is used in Datepicker as following.
<mat-form-field>
  <input matInput [matDatepicker]="seStDt" [min]="minDate" [max]="maxDate" formControlName="sessionStDate">
  ------
</mat-form-field> 
By using min and max properties,
a. The calendar will disable past and future dates and user cannot select date lesser than configured minimum date as well as date greater than configured maximum date.
b. If user manually enters out of the date range in input text, the Datepicker value will be invalid. We can display error messages by checking matDatepickerMin and matDatepickerMax error properties.

Suppose we have a FormGroup with following form control.
studentForm = this.formBuilder.group({
  sessionStDate: ['', Validators.required],
  ------
}); 
Our minimum and maximum dates are defined as follows.
minDate: Moment;
maxDate: Moment;
ngOnInit() {
  const currentYear = moment().year();
  this.minDate = moment([currentYear -1, 0, 1]);
  this.maxDate = moment([currentYear + 1, 11, 31])
} 
Find the HTML template code of min and max validation with error messages.
<mat-form-field>
  <mat-label>Session start date</mat-label>
  <input matInput [matDatepicker]="seStDt" [min]="minDate" [max]="maxDate" formControlName="sessionStDate">
  <mat-datepicker-toggle matSuffix [for]="seStDt"></mat-datepicker-toggle>
  <mat-datepicker #seStDt></mat-datepicker>

  <mat-error *ngIf="studentForm.get('sessionStDate').hasError('required')">
    Session start date required.
  </mat-error>    
  <mat-error *ngIf="studentForm.get('sessionStDate').hasError('matDatepickerMin')">
    Invalid minimum date.
  </mat-error>
  <mat-error *ngIf="studentForm.get('sessionStDate').hasError('matDatepickerMax')">
    Invalid maximum date.
  </mat-error>
</mat-form-field> 

Validation with matDatepickerFilter

Datepicker can be validated using matDatepickerFilter property of Datepicker input. The matDatepickerFilter accepts a function that returns Boolean. For true value date is valid and for false value date is invalid. The calendar will disable invalid dates and cannot be selected. But for manual entry of invalid date, we can display error message using its matDatepickerFilter error.
Find a function to be assigned to matDatepickerFilter property that will disable weekends.
myDateFilter = (m: Moment | null): boolean => {
  const day = (m || moment()).day();
  return day !== 0 && day !== 6;
} 
Find the HTML template code to use matDatepickerFilter property and matDatepickerFilter error.
<mat-form-field>
  <mat-label>Session close date</mat-label>
  <input matInput [matDatepicker]="seClDt" [matDatepickerFilter]="myDateFilter" formControlName="sessionClDate">
  <mat-datepicker-toggle matSuffix [for]="seClDt"></mat-datepicker-toggle>
  <mat-datepicker #seClDt></mat-datepicker>

  <mat-error *ngIf="studentForm.get('sessionClDate').hasError('matDatepickerFilter')">
    Weekends not allowed.
  </mat-error>
</mat-form-field> 

Using Custom Validator

We can create our own validator to validate Datepicker. Find a custom validator that creates invalidDOBYear error.
datepicker-validator.ts
import { ValidatorFn, AbstractControl } from '@angular/forms';
import { Moment } from 'moment';

export function datePickerValidator(): ValidatorFn {
  return (control: AbstractControl): { [key: string]: any } | null => {
    let forbidden = true;
    if (control.value) {
      const moment: Moment = control.value;
      if (moment.year() > 2000 ) {
        forbidden = false;
      }
    }
    return forbidden ? { 'invalidDOBYear': true } : null;
  };
} 
In the above code, we are using Moment because our demo application will import MomentDateModule which is based on moment.js. If our application imports MatNativeDateModule then we should use native JavaScript Date.
Now find the FormGroup which uses our custom validation.
studentForm = this.formBuilder.group({
  dateOfBirth: ['', [Validators.required, datePickerValidator()]],
  ------
}); 
Find the HTML template code that uses invalidDOBYear to display error message.
<mat-form-field appearance="fill">
  ------   
  <mat-error *ngIf="studentForm.get('dateOfBirth').hasError('invalidDOBYear')">
     Select year greater than 2000.
  </mat-error>        
</mat-form-field> 

Date Range Validation

Date range can be validated in Datepicker range selection. The Datepicker for date range selection is created using <mat-date-range-picker> and <mat-date-range-input>. From Datepicker calendar, we cannot select start date greater than end date but user can enter invalid dates manually in input text. To display error messages in this case, we need to use matStartDateInvalid and matEndDateInvalid error.
Suppose we have a FormGroup.
studentForm = this.formBuilder.group({
  ------
  admDateRange: this.formBuilder.group({
    startDate: '',
    endDate: ''
  })
}); 
Find the HTML template code to use matStartDateInvalid and matEndDateInvalid error.
<mat-form-field>
   <mat-label>Admission Date Range</mat-label>
   <mat-date-range-input [rangePicker]="admDateRangePicker"  formGroupName="admDateRange">
     <input matStartDate formControlName="startDate" placeholder="Start date">
     <input matEndDate formControlName="endDate" placeholder="End date">
   </mat-date-range-input>
   <mat-datepicker-toggle matSuffix [for]="admDateRangePicker"></mat-datepicker-toggle>
   <mat-date-range-picker #admDateRangePicker></mat-date-range-picker>

   <mat-error *ngIf="studentForm.get('admDateRange').get('startDate').hasError('matStartDateInvalid')">
     Invalid start date.
   </mat-error>
   <mat-error *ngIf="studentForm.get('admDateRange').get('endDate').hasError('matEndDateInvalid')">
     Invalid end date.
   </mat-error>
   <mat-error *ngIf="studentForm.get('admDateRange').get('startDate').invalid || studentForm.get('admDateRange').get('endDate').invalid">
     Valid date required.
   </mat-error>        
</mat-form-field> 


Complete Example

Find the complete demo application using moment.js.
student.component.html
<h3>Datepicker Validation</h3>
For manual date entry, use date format (DD-MM-YYYY). <br/><br/>
<form [formGroup]="studentForm" (ngSubmit)="onFormSubmit()">
  <mat-form-field>
    <mat-label>Student Name</mat-label>
    <input matInput formControlName="name">
    <mat-error *ngIf="studentForm.get('name').hasError('required')">
      Student name required.
    </mat-error>    
  </mat-form-field>
  <br/><br/>
  <mat-form-field appearance="fill">
    <mat-label>Date of Birth</mat-label>
    <input matInput [matDatepicker]="dob" formControlName="dateOfBirth">
    <mat-datepicker-toggle matSuffix [for]="dob"></mat-datepicker-toggle>
    <mat-datepicker #dob></mat-datepicker>

    <mat-error *ngIf="studentForm.get('dateOfBirth').hasError('required')">
      Valid date required.
    </mat-error>
    <mat-error *ngIf="studentForm.get('dateOfBirth').hasError('invalidDOBYear')">
      Select year greater than 2000.
    </mat-error>        
  </mat-form-field>  
  <br/><br/>
  <mat-form-field appearance="fill">
    <mat-label>Session start date</mat-label>
    <input matInput [matDatepicker]="seStDt" [min]="minDate" [max]="maxDate" formControlName="sessionStDate">
    <mat-datepicker-toggle matSuffix [for]="seStDt"></mat-datepicker-toggle>
    <mat-datepicker #seStDt></mat-datepicker>

    <mat-error *ngIf="studentForm.get('sessionStDate').hasError('required')">
      Valid date required.
    </mat-error>    
    <mat-error *ngIf="studentForm.get('sessionStDate').hasError('matDatepickerMin')">
      Invalid minimum date.
    </mat-error>
    <mat-error *ngIf="studentForm.get('sessionStDate').hasError('matDatepickerMax')">
      Invalid maximum date.
    </mat-error>
  </mat-form-field>  
  <br/><br/>
  <mat-form-field appearance="fill">
    <mat-label>Session close date</mat-label>
    <input matInput [matDatepicker]="seClDt" [matDatepickerFilter]="myDateFilter" formControlName="sessionClDate">
    <mat-datepicker-toggle matSuffix [for]="seClDt"></mat-datepicker-toggle>
    <mat-datepicker #seClDt></mat-datepicker>

    <mat-error *ngIf="studentForm.get('sessionClDate').hasError('required')">
      Valid date required.
    </mat-error>    
    <mat-error *ngIf="studentForm.get('sessionClDate').hasError('matDatepickerFilter')">
      Weekends not allowed.
    </mat-error>
  </mat-form-field>  
  <br/><br/>
  <mat-form-field appearance="fill">
    <mat-label>Admission Date Range</mat-label>
    <mat-date-range-input [rangePicker]="admDateRangePicker"  formGroupName="admDateRange">
      <input matStartDate formControlName="startDate" placeholder="Start date">
      <input matEndDate formControlName="endDate" placeholder="End date">
    </mat-date-range-input>
    <mat-datepicker-toggle matSuffix [for]="admDateRangePicker"></mat-datepicker-toggle>
    <mat-date-range-picker #admDateRangePicker></mat-date-range-picker>

    <mat-error *ngIf="studentForm.get('admDateRange').get('startDate').hasError('matStartDateInvalid')">
      Invalid start date.
    </mat-error>
    <mat-error *ngIf="studentForm.get('admDateRange').get('endDate').hasError('matEndDateInvalid')">
      Invalid end date.
    </mat-error>
    <mat-error *ngIf="studentForm.get('admDateRange').get('startDate').invalid || studentForm.get('admDateRange').get('endDate').invalid">
      Valid date required.
    </mat-error>        
  </mat-form-field>
  <br/><br/><br/>
  <button mat-raised-button>Submit</button>
</form> 
student.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { StudentService } from './student.service';
import { datePickerValidator } from './datepicker-validator';
import * as _moment from 'moment';
import { Moment } from 'moment';

const moment = _moment;

@Component({
  selector: 'app-student',
  templateUrl: './student.component.html'
})
export class StudentComponent implements OnInit {
  minDate: Moment;
  maxDate: Moment;
  myDateFilter = (m: Moment | null): boolean => {
    const day = (m || moment()).day();
    return day !== 0 && day !== 6;
  }   
  constructor(private formBuilder: FormBuilder, private studentService: StudentService) { }
  ngOnInit() {
    const currentYear = moment().year();
    this.minDate = moment([currentYear -1, 0, 1]);
    this.maxDate = moment([currentYear + 1, 11, 31])
  }
  studentForm = this.formBuilder.group({
    name: ['', Validators.required],
    dateOfBirth: ['', [Validators.required, datePickerValidator()]],
    sessionStDate: ['', Validators.required],
    sessionClDate: ['', Validators.required],
    admDateRange: this.formBuilder.group({
      startDate: '',
      endDate: ''
    })
  });
  onFormSubmit() {
    this.studentService.saveStudent(this.studentForm.value);
    this.studentForm.reset();
  }
} 
student.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class StudentService {
  saveStudent(student) {
    console.log(JSON.stringify(student));
  }
} 
my-date-formats.ts
export const MY_DATE_FORMATS = {
    parse: {
      dateInput: 'DD-MM-YYYY',
    },
    display: {
      dateInput: 'DD-MM-YYYY',
      monthYearLabel: 'MMM YYYY',
      dateA11yLabel: 'LL',
      monthYearA11yLabel: 'MMMM YYYY'
    },
}; 
app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
      <app-student></app-student>
  `
})
export class AppComponent {
} 
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule }    from '@angular/forms'; 
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatInputModule } from '@angular/material/input';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MomentDateModule } from '@angular/material-moment-adapter';
import { MAT_DATE_FORMATS } from '@angular/material/core';

import { AppComponent } from './app.component';
import { StudentComponent } from './student.component';
import { MY_DATE_FORMATS } from './my-date-formats';

@NgModule({
  declarations: [
    AppComponent,
    StudentComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    BrowserAnimationsModule,
    MatInputModule, 
    MatDatepickerModule,
    MomentDateModule
  ],
  providers: [
    { provide: MAT_DATE_FORMATS, useValue: MY_DATE_FORMATS }
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { } 

Run Application

To run the application, find the steps.
1. Install Angular CLI using link.
2. Install Angular Material using link.
3. Install moment.js.
npm install moment --save 
4. Download source code using download link given below on this page.
5. Use downloaded src in your Angular CLI application.
6. Run ng serve using command prompt.
7. Access the URL http://localhost:4200
Find the print screen of the output.
Angular Material Datepicker Validation

References

Datepicker
Moment.js Documentation

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us