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.