Home > database >  Angular material date-picker validation
Angular material date-picker validation

Time:03-21

I was struggling to add validation to date-picker. This is a stackblitz link. You can see the codebase

My date-picker should just allow to DD MMM YYYY format. It should not allow DD-MM-YY, DD/MM/YYYY, and such.

I put a warning message. It works correctly. However, the date picker's own border validation does not work properly. How Can I handle this problem? The date picker should not be required.

This is inside of the typescript file.

export const MY_FORMATS = {
parse: {
 dateInput: 'DD MMM YYYY',
},
display: {
 dateInput: 'DD MMM YYYY',
 monthYearLabel: 'MMMM YYYY',
 dateA11yLabel: 'DD MM YYYY',
 monthYearA11yLabel: 'MMMM YYYY',
 },
};
@Component({
  selector: 'datepicker-overview-example',
  templateUrl: 'datepicker-overview-example.html',
  styleUrls: ['datepicker-overview-example.css'],
  providers: [
  {
   provide: DateAdapter,
   useClass: MomentDateAdapter,
   deps: [MAT_DATE_LOCALE],
  },
  { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
 ],
})

export class DatepickerOverviewExample {
 regexPattern = /^(([1-9])|([0][1-9])|([1-2][0-9])|([3][0-1]))(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\d{4}$/gi;

 date = new FormControl('', [Validators.pattern(this.regexPattern)]);

 getErrorMessage(val: string): string {
  const regexPattern = /^(([1-9])|([0][1-9])|([1-2][0-9])|([3][0-1]))(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\d{4}$/gi;
 
  const value = val.replace(/\s /g, '');
  const isValid = regexPattern.test(value);
  console.log(isValid);
  // console.log(this.date.valid);

  if (!isValid && val !== '') {
   return 'Invalid input: Please input a string in the form of DD MMM YYYY';
  }

  return '';
 }
}

Here is the template.

<mat-form-field appearance="legacy">
 <input
  matInput
  [matDatepicker]="picker"
  placeholder="Choose a date"
  #pickerInput
  [formControl]="date"
 />
 <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
 <mat-datepicker #picker></mat-datepicker>
 <mat-error *ngIf="date.invalid">{{getErrorMessage(pickerInput.value)}}</mat-error>
</mat-form-field>

Thanks in advance!

CodePudding user response:

I abstracted away from valid check to create a custom validator, it should work. Your pattern check doesn't check for ISO string as you might expect, I think it checked against the internal Moment Obj angular datepicker is using.

export function dateRegexValidator(
  control: AbstractControl
): { [key: string]: boolean } | null {
  const regexPattern = /^(([1-9])|([0][1-9])|([1-2][0-9])|([3][0-1]))(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\d{4}$/gi;
  let val = control.value;
  const isValid = regexPattern.test(val);

  if (isValid) {
    return { dateRegex: true };
  }
  return null;
}
<mat-form-field appearance="legacy">
  <input
    matInput
    [matDatepicker]="picker"
    placeholder="Choose a date"
    #pickerInput
    [formControl]="date"
  />
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker></mat-datepicker>
  <mat-error *ngIf="date.errors?.dateRegexValidator"
    >{{getErrorMessage(pickerInput.value)}}</mat-error
  >
</mat-form-field>

Example: https://stackblitz.com/edit/angular-b1auah-nvrb3c?file=src/app/datepicker-overview-example.ts

CodePudding user response:

The error comes from the fact that Validators.pattern() assumes control.value is a string. However, control.value is an object.

console.log(this.date.value);
Object { _isAMomentObject: true, _i: {…}, _isUTC: false, _pf: {…}, _locale: {…}, _d: Date Wed Mar 23 2022 00:00:00 GMT-0400 (Eastern Daylight Saving Time), _isValid: true }

Whereas in your getErrorMessage() call you are getting the value of the HTMLInputElement not the FormControl.

You are using a component with built in validation and auto-format, so a validator is not necessary. You've already supplied the format so you can trust it to do it's job.

To get the formatted string you can do

  @ViewChild('pickerInput') pickerInput?: ElementRef;
  get formattedDate(): string | undefined {
    return this.pickerInput?.nativeElement.value;
  }

Or convert the object in this.date.value manually. You can always double check that the string is valid before submitting, which would indicate the date picker is broken.

  • Related