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 c2bc3d1e10..7b911c3708 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 @@ -2,6 +2,7 @@ import { FormControl } from '@angular/forms'; import { validateRange } from '../validators'; import { validateCreditCard } from '../validators/credit-card.validator'; import { validateRequired } from '../validators/required.validator'; +import { validateStringLength } from '../validators/string-length.validator'; describe('Validators', () => { describe('Credit Card Validator', () => { @@ -110,4 +111,40 @@ describe('Validators', () => { expect(control.valid).toBe(true); }); }); + + describe('String Length Validator', () => { + test.each` + input | options | expected + ${null} | ${undefined} | ${null} + ${undefined} | ${undefined} | ${null} + ${''} | ${undefined} | ${null} + ${null} | ${{ minimumLength: 0 }} | ${null} + ${undefined} | ${{ minimumLength: 0 }} | ${null} + ${''} | ${{ minimumLength: 0 }} | ${null} + ${null} | ${{ minimumLength: 3 }} | ${{ minlength: 3 }} + ${undefined} | ${{ minimumLength: 3 }} | ${{ minlength: 3 }} + ${''} | ${{ minimumLength: 3 }} | ${{ minlength: 3 }} + ${'ab'} | ${{ minimumLength: 3 }} | ${{ minlength: 3 }} + ${'abp'} | ${{ minimumLength: 3 }} | ${null} + ${'abp'} | ${{ maximumLength: 2 }} | ${{ maxlength: 2 }} + ${'abp'} | ${{ maximumLength: 3 }} | ${null} + `( + 'should return $expected when input is $input and options are $options', + ({ input, options, expected }) => { + const control = new FormControl(input, [validateStringLength(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, [validateStringLength({ minimumLength: 3 })]); + // control is not dirty + + expect(control.valid).toBe(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 df2a6f9c1b..ad7c29ed83 100644 --- a/npm/ng-packs/packages/core/src/lib/validators/index.ts +++ b/npm/ng-packs/packages/core/src/lib/validators/index.ts @@ -2,13 +2,16 @@ import { Validators } from '@angular/forms'; import { validateCreditCard } from './credit-card.validator'; import { validateRange } from './range.validator'; import { validateRequired } from './required.validator'; +import { validateStringLength } from './string-length.validator'; export * from './credit-card.validator'; export * from './range.validator'; export * from './required.validator'; +export * from './string-length.validator'; export const AbpValidators = { creditCard: validateCreditCard, email: () => Validators.email, range: validateRange, required: validateRequired, + stringLength: validateStringLength, }; diff --git a/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts b/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts new file mode 100644 index 0000000000..24c98a2435 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/validators/string-length.validator.ts @@ -0,0 +1,34 @@ +import { AbstractControl, ValidatorFn } from '@angular/forms'; + +export interface StringLengthError { + maxlength?: number; + minlength?: number; +} + +export interface StringLengthOptions { + maximumLength?: number; + minimumLength?: number; +} + +export function validateStringLength({ + maximumLength = Infinity, + minimumLength = 0, +}: StringLengthOptions = {}): ValidatorFn { + return (control: AbstractControl): StringLengthError | null => { + if (control.pristine) return null; + + if (!control.value && minimumLength) return { minlength: minimumLength }; + + const value = String(control.value); + + return getMinLengthError(value, minimumLength) || getMaxLengthError(value, maximumLength); + }; +} + +function getMaxLengthError(value: string, maxlength: number): StringLengthError { + return value.length > maxlength ? { maxlength } : null; +} + +function getMinLengthError(value: string, minlength: number): StringLengthError { + return value.length < minlength ? { minlength } : null; +}