From bc66979a09bf42d40ff71647ab2dbeb2a950f714 Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Thu, 21 May 2020 02:26:29 +0300 Subject: [PATCH] feat: add range validator --- .../core/src/lib/tests/validators.spec.ts | 37 +++++++++++++++++++ .../packages/core/src/lib/validators/index.ts | 3 ++ .../src/lib/validators/range.validator.ts | 30 +++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 npm/ng-packs/packages/core/src/lib/validators/range.validator.ts diff --git a/npm/ng-packs/packages/core/src/lib/tests/validators.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/validators.spec.ts index 62c111a218..c2bc3d1e10 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/validators.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/validators.spec.ts @@ -1,4 +1,5 @@ import { FormControl } from '@angular/forms'; +import { validateRange } from '../validators'; import { validateCreditCard } from '../validators/credit-card.validator'; import { validateRequired } from '../validators/required.validator'; @@ -41,6 +42,42 @@ describe('Validators', () => { }); }); + describe('Range Validator', () => { + test.each` + input | options | expected + ${null} | ${undefined} | ${{ min: 0, max: Infinity }} + ${undefined} | ${undefined} | ${{ min: 0, max: Infinity }} + ${''} | ${undefined} | ${{ min: 0, max: Infinity }} + ${0} | ${undefined} | ${null} + ${Infinity} | ${undefined} | ${null} + ${null} | ${{ minimum: 0 }} | ${{ min: 0, max: Infinity }} + ${undefined} | ${{ minimum: 0 }} | ${{ min: 0, max: Infinity }} + ${''} | ${{ minimum: 0 }} | ${{ min: 0, max: Infinity }} + ${0} | ${{ minimum: 0 }} | ${null} + ${2} | ${{ minimum: 3, maximum: 5 }} | ${{ min: 3, max: 5 }} + ${3} | ${{ minimum: 3, maximum: 5 }} | ${null} + ${5} | ${{ minimum: 3, maximum: 5 }} | ${null} + ${6} | ${{ minimum: 3, maximum: 5 }} | ${{ min: 3, max: 5 }} + `( + 'should return $expected when input is $input and options are $options', + ({ input, options, expected }) => { + const control = new FormControl(input, [validateRange(options)]); + control.markAsDirty({ onlySelf: true }); + control.updateValueAndValidity({ onlySelf: true, emitEvent: false }); + + expect(control.errors).toEqual(expected); + }, + ); + + it('should return null when control is pristine', () => { + const invalidUrl = ''; + const control = new FormControl(invalidUrl, [validateRange({ minimum: 3 })]); + // control is not dirty + + expect(control.valid).toBe(true); + }); + }); + describe('Required Validator', () => { const error = { required: true }; diff --git a/npm/ng-packs/packages/core/src/lib/validators/index.ts b/npm/ng-packs/packages/core/src/lib/validators/index.ts index d353ed0515..df2a6f9c1b 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/index.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/index.ts @@ -1,11 +1,14 @@ import { Validators } from '@angular/forms'; import { validateCreditCard } from './credit-card.validator'; +import { validateRange } from './range.validator'; import { validateRequired } from './required.validator'; export * from './credit-card.validator'; +export * from './range.validator'; export * from './required.validator'; export const AbpValidators = { creditCard: validateCreditCard, email: () => Validators.email, + range: validateRange, required: validateRequired, }; diff --git a/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts new file mode 100644 index 0000000000..15a9862fcd --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/validators/range.validator.ts @@ -0,0 +1,30 @@ +import { AbstractControl, ValidatorFn } from '@angular/forms'; + +export interface RangeError { + max: number; + min: number; +} + +export interface RangeOptions { + maximum?: number; + minimum?: number; +} + +export function validateRange({ maximum = Infinity, minimum = 0 }: RangeOptions = {}): ValidatorFn { + return (control: AbstractControl): RangeError | null => { + if (control.pristine) return null; + + if (['', null, undefined].indexOf(control.value) > -1) return { min: minimum, max: maximum }; + + const value = Number(control.value); + return getMinError(value, minimum, maximum) || getMaxError(value, maximum, minimum); + }; +} + +function getMaxError(value: number, max: number, min: number): RangeError { + return value > max ? { max, min } : null; +} + +function getMinError(value: number, min: number, max: number): RangeError { + return value < min ? { min, max } : null; +}