Skip to content

Commit 8bb0530

Browse files
committed
feat(universal): add min and max Date validators
1 parent b75c6af commit 8bb0530

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed

src/components/universal/universal-validators.spec.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,76 @@ describe("Universal validators service", () => {
237237
expect(validated).toEqual({ max: { required: 2, actual: "3" } });
238238
});
239239
});
240+
241+
describe("maxDate", () => {
242+
it("should work for empty control", () => {
243+
const control: FormControl = new FormControl("");
244+
const validated = UniversalValidators.maxDate(new Date())(control);
245+
expect(validated).toBeUndefined();
246+
});
247+
248+
it("should work for valid maxDate", () => {
249+
const control: FormControl = new FormControl("2012-12-24");
250+
const validated = UniversalValidators.maxDate(new Date())(control);
251+
expect(validated).toBeUndefined();
252+
});
253+
254+
it("should work for valid maxDate", () => {
255+
const date = new Date();
256+
const control: FormControl = new FormControl(date.getTime());
257+
const validated = UniversalValidators.maxDate(date)(control);
258+
expect(validated).toBeUndefined();
259+
});
260+
261+
it("should work for invalid date", () => {
262+
const date = new Date();
263+
const control: FormControl = new FormControl("broken");
264+
const validated = UniversalValidators.maxDate(date)(control);
265+
expect(validated).toEqual({ dateRequired: true });
266+
});
267+
268+
it("should work for invalid maxDate", () => {
269+
const currentDate = new Date();
270+
const requiredDate = new Date("2012-12-24");
271+
const control: FormControl = new FormControl(currentDate);
272+
const validated = UniversalValidators.maxDate(requiredDate)(control);
273+
expect(validated).toEqual({ maxDate: { required: requiredDate, actual: currentDate } });
274+
});
275+
});
276+
277+
describe("minDate", () => {
278+
it("should work for empty control", () => {
279+
const control: FormControl = new FormControl("");
280+
const validated = UniversalValidators.minDate(new Date())(control);
281+
expect(validated).toBeUndefined();
282+
});
283+
284+
it("should work for valid minDate", () => {
285+
const control: FormControl = new FormControl("2020-12-24");
286+
const validated = UniversalValidators.minDate(new Date("2012-12-24"))(control);
287+
expect(validated).toBeUndefined();
288+
});
289+
290+
it("should work for valid minDate", () => {
291+
const date = new Date();
292+
const control: FormControl = new FormControl(date.getTime());
293+
const validated = UniversalValidators.minDate(date)(control);
294+
expect(validated).toBeUndefined();
295+
});
296+
297+
it("should work for invalid date", () => {
298+
const date = new Date();
299+
const control: FormControl = new FormControl("broken");
300+
const validated = UniversalValidators.minDate(date)(control);
301+
expect(validated).toEqual({ dateRequired: true });
302+
});
303+
304+
it("should work for invalid minDate", () => {
305+
const currentDate = new Date("2012-12-24");
306+
const requiredDate = new Date();
307+
const control: FormControl = new FormControl(currentDate);
308+
const validated = UniversalValidators.minDate(requiredDate)(control);
309+
expect(validated).toEqual({ minDate: { required: requiredDate, actual: currentDate } });
310+
});
311+
});
240312
});

src/components/universal/universal-validators.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,34 @@ export class UniversalValidators {
115115
};
116116
return validator;
117117
}
118+
119+
public static minDate(minDate: Date) {
120+
const validator = (control: AbstractControl): ValidationErrors => {
121+
if (AbstractControlUtil.isNotPresent(control)) return undefined;
122+
const date: Date = new Date(control.value);
123+
if (isNaN(date.getTime())) {
124+
return { dateRequired: true };
125+
}
126+
if (date.getTime() >= minDate.getTime()) {
127+
return undefined;
128+
}
129+
return { minDate: { required: minDate, actual: date } };
130+
};
131+
return validator;
132+
}
133+
134+
public static maxDate(minDate: Date) {
135+
const validator = (control: AbstractControl): ValidationErrors => {
136+
if (AbstractControlUtil.isNotPresent(control)) return undefined;
137+
const date: Date = new Date(control.value);
138+
if (isNaN(date.getTime())) {
139+
return { dateRequired: true };
140+
}
141+
if (date.getTime() <= minDate.getTime()) {
142+
return undefined;
143+
}
144+
return { maxDate: { required: minDate, actual: date } };
145+
};
146+
return validator;
147+
}
118148
}

src/components/universal/universal.directive.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,77 @@ export class MinValidatorDirective implements Validator, OnInit, OnChanges {
197197
this.onChange = fn;
198198
}
199199
}
200+
201+
@Directive({
202+
selector: "input[type=text][minDate][formControlName],input[type=text][minDate][formControl],input[type=text][minDate][ngModel]",
203+
providers: [
204+
{
205+
provide: NG_VALIDATORS,
206+
// tslint:disable-next-line:no-forward-ref
207+
useExisting: forwardRef(() => MinDateValidatorDirective),
208+
multi: true,
209+
},
210+
],
211+
})
212+
export class MinDateValidatorDirective implements Validator, OnInit, OnChanges {
213+
@Input() minDate: string;
214+
215+
private validator: ValidatorFn;
216+
private onChange: () => void;
217+
218+
ngOnInit() {
219+
this.validator = UniversalValidators.minDate(new Date(this.minDate));
220+
}
221+
222+
ngOnChanges(changes: SimpleChanges): void {
223+
if (changes.minDate && !changes.minDate.isFirstChange()) {
224+
this.validator = UniversalValidators.minDate(changes.min.currentValue);
225+
this.onChange();
226+
}
227+
}
228+
229+
validate(c: AbstractControl): ValidationErrors {
230+
return this.validator(c);
231+
}
232+
233+
registerOnValidatorChange(fn: () => void): void {
234+
this.onChange = fn;
235+
}
236+
}
237+
238+
@Directive({
239+
selector: "input[type=text][maxDate][formControlName],input[type=text][maxDate][formControl],input[type=text][maxDate][ngModel]",
240+
providers: [
241+
{
242+
provide: NG_VALIDATORS,
243+
// tslint:disable-next-line:no-forward-ref
244+
useExisting: forwardRef(() => MaxDateValidatorDirective),
245+
multi: true,
246+
},
247+
],
248+
})
249+
export class MaxDateValidatorDirective implements Validator, OnInit, OnChanges {
250+
@Input() maxDate: string;
251+
252+
private validator: ValidatorFn;
253+
private onChange: () => void;
254+
255+
ngOnInit() {
256+
this.validator = UniversalValidators.maxDate(new Date(this.maxDate));
257+
}
258+
259+
ngOnChanges(changes: SimpleChanges): void {
260+
if (changes.maxDate && !changes.maxDate.isFirstChange()) {
261+
this.validator = UniversalValidators.maxDate(changes.min.currentValue);
262+
this.onChange();
263+
}
264+
}
265+
266+
validate(c: AbstractControl): ValidationErrors {
267+
return this.validator(c);
268+
}
269+
270+
registerOnValidatorChange(fn: () => void): void {
271+
this.onChange = fn;
272+
}
273+
}

0 commit comments

Comments
 (0)