Skip to content

Instantly share code, notes, and snippets.

@kmaida
Last active August 21, 2020 14:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kmaida/9fc502c722ed36fca2aa09ecfce46d1e to your computer and use it in GitHub Desktop.
Save kmaida/9fc502c722ed36fca2aa09ecfce46d1e to your computer and use it in GitHub Desktop.
Angular Date Validator - directive and factory - validates strings m/d/yyyy
// MM/DD/YYYY, M/D/YYYY
const DATE_REGEX = new RegExp(/^(\d{2}|\d{1})\/(\d{2}|\d{1})\/\d{4}$/);
export { DATE_REGEX };
<input
id="endDate"
name="endDate"
type="text"
class="form-control"
#endDate="ngModel"
appDateField
required
[(ngModel)]="form.endDate">
import { Directive } from '@angular/core';
import { NG_VALIDATORS, Validator, ValidatorFn, FormControl } from '@angular/forms';
import { dateValidator } from './validateDate.factory';
@Directive({
selector: '[appDateField]',
providers: [
{ provide: NG_VALIDATORS, useExisting: ValidateDateDirective, multi: true }
]
})
export class ValidateDateDirective implements Validator {
private _valFn: ValidatorFn;
constructor() {
this._valFn = dateValidator();
}
validate(control: FormControl) {
return this._valFn(control);
}
}
import { AbstractControl, ValidatorFn } from '@angular/forms';
import { DATE_REGEX } from './formUtils.factory';
export function dateValidator(): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
const dateStr = control.value;
// Length of months (will update for leap years)
const monthLength = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
// Object to return if date is invalid
const invalidObj = { 'date': true };
// First check for m/d/yyyy or mm/dd/yyyy format
// If the pattern is wrong, don't validate dates yet
if (!DATE_REGEX.test(dateStr)) {
return null;
}
// Parse the date input to integers
const parts = dateStr.split('/');
const month = parseInt(parts[0], 10);
const day = parseInt(parts[1], 10);
const year = parseInt(parts[2], 10);
// Make sure date is in range
if (year < 2000 || year > 3000 || month === 0 || month > 12) {
return invalidObj;
}
// Adjust for leap years
if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) {
monthLength[1] = 29;
}
// Check the range of the day
if (!(day > 0 && day <= monthLength[month - 1])) {
return invalidObj;
};
return null;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment