Skip to content

Commit

Permalink
fix(if-validator): exclude individual validators from composition to …
Browse files Browse the repository at this point in the history
…allow presence checks (#273)
  • Loading branch information
rlmestre authored Mar 24, 2024
1 parent ae2d9ef commit 92a614c
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 6 deletions.
134 changes: 134 additions & 0 deletions libs/ngxtension/if-validator/src/if-validator.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { FormControl } from '@angular/forms';
import { of } from 'rxjs';
import { ifAsyncValidator, ifValidator } from './if-validator';

describe('ifValidator', () => {
it('should return null if the condition is false', () => {
const control = new FormControl();
const condition = () => false;
const validatorFn = () => null;

const validator = ifValidator(condition, validatorFn);
const result = validator(control);

expect(result).toBeNull();
});

it('should return the result of a provided validatorFn if the condition is true', () => {
const control = new FormControl('a');
const condition = (ctrl: FormControl) => ctrl.value !== 'a';
const validatorFn = () => ({ invalid: true });

const validator = ifValidator(condition, validatorFn);

const result = validator(control);
expect(result).toBeNull();

control.setValue('b');
const newResult = validator(control);
expect(newResult).toEqual({ invalid: true });
});

it('should return null if an array with no items is provided', () => {
const control = new FormControl();
const condition = () => true;

const validator = ifValidator(condition, []);
const result = validator(control);

expect(result).toBeNull();
});

it('should return the result of a provided validatorFn', () => {
const control = new FormControl();
const condition = () => true;
const validatorFn = () => ({ invalid: true });

const validator = ifValidator(condition, validatorFn);
const result = validator(control);

expect(result).toEqual({ invalid: true });
});

it('should be able to query the presence of a provided validatorFn', () => {
const condition = () => true;
const validatorFn = () => ({ invalid: true });

const validator = ifValidator(condition, validatorFn);
const control = new FormControl(null, validator);
const hasValidator = control.hasValidator(validator);

expect(hasValidator).toBe(true);
});

it('should return the result of a sole validatorFn provided in an array', () => {
const control = new FormControl();
const condition = () => true;
const validatorFn = () => ({ invalid: true });

const validator = ifValidator(condition, [validatorFn]);
const result = validator(control);

expect(result).toEqual({ invalid: true });
});

it('should be able to query the presence of a sole validatorFn provided in an array', () => {
const condition = () => true;
const validatorFn = () => ({ invalid: true });

const validator = ifValidator(condition, [validatorFn]);
const control = new FormControl(null, validator);
const hasValidator = control.hasValidator(validator);

expect(hasValidator).toBe(true);
});

it('should return the result of multiple provided validators', () => {
const control = new FormControl();
const condition = () => true;
const validatorFn1 = () => ({ bad: true });
const validatorFn2 = () => ({ worse: true });

const validator = ifValidator(condition, [validatorFn1, validatorFn2]);
const result = validator(control);

expect(result).toEqual({ bad: true, worse: true });
});
});

describe('ifAsyncValidator', () => {
it('should return null if the condition is false', () => {
const control = new FormControl();
const condition = () => false;
const validatorFn = () => of(null);

const validator = ifAsyncValidator(condition, validatorFn);
control.setAsyncValidators(validator);

expect(control.errors).toBe(null);
});

it('should return the result of a provided async validatorFn if the condition is true', () => {
const control = new FormControl('a');
const condition = (ctrl: FormControl) => ctrl.value !== 'a';
const validatorFn = () => of({ invalid: true });

const validator = ifAsyncValidator(condition, validatorFn);
control.setAsyncValidators(validator);

control.setValue('b');

expect(control.errors).toEqual({ invalid: true });
});

it('should be able to query the presence of a provided async validatorFn', () => {
const condition = () => true;
const validatorFn = () => of({ invalid: true });

const validator = ifAsyncValidator(condition, validatorFn);
const control = new FormControl(null, { asyncValidators: validator });
const hasValidator = control.hasAsyncValidator(validator);

expect(hasValidator).toBe(true);
});
});
23 changes: 17 additions & 6 deletions libs/ngxtension/if-validator/src/if-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,24 @@ export function ifValidator(
validatorFn: ValidatorFn | ValidatorFn[],
): ValidatorFn {
return (control: AbstractControl) => {
if (!validatorFn || !condition(<FormControl>control)) {
if (!condition(<FormControl>control)) {
return null;
}
const validatorFns = Array.isArray(validatorFn)
? (validatorFn as ValidatorFn[])
: [validatorFn];
return Validators.compose(validatorFns)?.(control) ?? null;

if (!Array.isArray(validatorFn)) {
return validatorFn(control);
}

if (validatorFn.length === 0) {
return null;
}

if (validatorFn.length === 1) {
return validatorFn[0](control);
}

const composed = Validators.compose(validatorFn);
return composed ? composed(control) : null;
};
}

Expand All @@ -33,7 +44,7 @@ export function ifAsyncValidator(
validatorFn: AsyncValidatorFn,
): AsyncValidatorFn {
return (control: AbstractControl) => {
if (!validatorFn || !condition(<FormControl>control)) {
if (!condition(<FormControl>control)) {
return of(null);
}

Expand Down

0 comments on commit 92a614c

Please sign in to comment.