From 84b1f4d22cbe0a6a098cfd9381f0dd31e9d2c123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Udo=20Sch=C3=B6fer?= Date: Sat, 1 Jul 2017 03:03:16 +0200 Subject: [PATCH] Validators processing refactored (#424) --- example/app/basic/basic-example.model.ts | 6 +- modules/core/src/core.utils.ts | 13 +++ .../src/model/dynamic-form-control.model.ts | 8 +- .../src/service/dynamic-form.service.spec.ts | 16 ++-- .../core/src/service/dynamic-form.service.ts | 89 ++++++++----------- 5 files changed, 69 insertions(+), 63 deletions(-) diff --git a/example/app/basic/basic-example.model.ts b/example/app/basic/basic-example.model.ts index 823e1e592..d90876be6 100644 --- a/example/app/basic/basic-example.model.ts +++ b/example/app/basic/basic-example.model.ts @@ -8,6 +8,7 @@ import { DynamicFormArrayModel, DynamicFormGroupModel } from "@ng2-dynamic-forms/core"; +import { customValidator } from "../app.module"; export const BASIC_EXAMPLE_MODEL = [ @@ -48,7 +49,10 @@ export const BASIC_EXAMPLE_MODEL = [ required: null, minLength: 2, maxLength: 5, - customValidator: null + customValidator: { + name: customValidator.name, + args: null + } }, errorMessages: { required: "{{label}} is required", diff --git a/modules/core/src/core.utils.ts b/modules/core/src/core.utils.ts index b443d4c00..07ebea03c 100644 --- a/modules/core/src/core.utils.ts +++ b/modules/core/src/core.utils.ts @@ -28,6 +28,19 @@ export class Utils { return typeof value === "object"; } + static isTrueObject(value: any): boolean { + return Utils.isDefined(value) && Utils.isObject(value); + } + + static isValidatorConfig(value: any): boolean { + + if (Utils.isTrueObject(value)) { + return value.hasOwnProperty("name") && value.hasOwnProperty("args"); + } + + return false; + } + static isString(value: any): boolean { return typeof value === "string"; } diff --git a/modules/core/src/model/dynamic-form-control.model.ts b/modules/core/src/model/dynamic-form-control.model.ts index 7cb1dc066..f0086a9f1 100644 --- a/modules/core/src/model/dynamic-form-control.model.ts +++ b/modules/core/src/model/dynamic-form-control.model.ts @@ -3,7 +3,13 @@ import { Subject } from "rxjs/Subject"; import { serializable, serialize } from "../decorator/serializable.decorator"; import { Utils } from "../core.utils"; -export type DynamicValidatorsMap = { [validatorName: string]: any }; +export interface DynamicValidatorConfig { + + name: string; + args: any; +} + +export type DynamicValidatorsMap = { [validatorName: string]: any | DynamicValidatorConfig }; export interface Cls { diff --git a/modules/core/src/service/dynamic-form.service.spec.ts b/modules/core/src/service/dynamic-form.service.spec.ts index 06469cdc4..fe596fa63 100644 --- a/modules/core/src/service/dynamic-form.service.spec.ts +++ b/modules/core/src/service/dynamic-form.service.spec.ts @@ -186,7 +186,7 @@ describe("DynamicFormService test suite", () => { let json = JSON.stringify(testModel), formModel = service.fromJSON(json); - expect(Array.isArray(formModel)).toBe(true); + expect(Array.isArray(formModel) as boolean).toBe(true); expect(formModel[0] instanceof DynamicSelectModel).toBe(true); expect(formModel[1] instanceof DynamicInputModel).toBe(true); @@ -459,23 +459,17 @@ describe("DynamicFormService test suite", () => { expect(validators.length === Object.keys(config).length).toBe(true); }); - it("should resolve custom async validators from config correctly", () => { + it("should resolve custom async validators from config correctly", inject([NG_ASYNC_VALIDATORS], (NG_ASYNC_VALIDATORS: any) => { let config: any = {required: null, maxLength: 7, testAsyncValidator: null}, - validators = service.getAsyncValidators(config); + validators = service.getValidators(config, NG_ASYNC_VALIDATORS); expect(validators.length === Object.keys(config).length).toBe(true); - }); + })); it("should throw when validator is not provided via NG_VALIDATORS", () => { expect(() => service.getValidatorFn("test", null)) - .toThrow(new Error(`validator "test" is not provided via NG_VALIDATORS`)); - }); - - it("should throw when validator is not provided via NG_ASYNC_VALIDATORS", () => { - - expect(() => service.getAsyncValidatorFn("test", null)) - .toThrow(new Error(`async validator "test" is not provided via NG_ASYNC_VALIDATORS`)); + .toThrow(new Error(`validator "test" is not provided via NG_VALIDATORS or NG_ASYNC_VALIDATORS`)); }); }); \ No newline at end of file diff --git a/modules/core/src/service/dynamic-form.service.ts b/modules/core/src/service/dynamic-form.service.ts index 4fc86fceb..5eebb87b7 100644 --- a/modules/core/src/service/dynamic-form.service.ts +++ b/modules/core/src/service/dynamic-form.service.ts @@ -10,7 +10,10 @@ import { NG_VALIDATORS, NG_ASYNC_VALIDATORS, AbstractControl } from "@angular/forms"; -import { DynamicFormControlModel, DynamicValidatorsMap } from "../model/dynamic-form-control.model"; +import { + DynamicFormControlModel, DynamicValidatorConfig, + DynamicValidatorsMap +} from "../model/dynamic-form-control.model"; import { DynamicFormValueControlModel, DynamicFormControlValue } from "../model/dynamic-form-value-control.model"; import { DynamicFormArrayModel, @@ -63,72 +66,58 @@ export class DynamicFormService { } - getCustomValidatorFn(validatorName: string): ValidatorFn | null { - - let validatorFn = null; - - if (this.NG_VALIDATORS) { - - validatorFn = this.NG_VALIDATORS.find(validatorFn => { - return validatorName === validatorFn.name || (validatorFn(new FormControl()) as Object).hasOwnProperty(validatorName); - }); - } - - return validatorFn; - } + getValidatorFn(validatorName: string, validatorArgs?: any, + validatorFnToken: any = this.NG_VALIDATORS): ValidatorFn | AsyncValidatorFn | never { + let validatorFn: Function | null = null; - getCustomAsyncValidatorFn(asyncValidatorName: string): AsyncValidatorFn | null { + if (Validators.hasOwnProperty(validatorName)) { // Angular Standard Validators - let asyncValidatorFn = null; + validatorFn = (Validators as any)[validatorName]; - if (this.NG_ASYNC_VALIDATORS) { + } else if (validatorFnToken) { // Custom Validators - asyncValidatorFn = this.NG_ASYNC_VALIDATORS.find(asyncValidatorFn => { - return asyncValidatorName === asyncValidatorFn.name; - }); + validatorFn = validatorFnToken.find((validatorFn: any) => validatorFn.name === validatorName); } - return asyncValidatorFn; - } - - - getValidatorFn(validatorName: string, validatorArgs?: any): ValidatorFn | never { - - let validatorFn: Function | null = (Validators as any)[validatorName] || this.getCustomValidatorFn(validatorName); - if (!Utils.isFunction(validatorFn)) { - throw new Error(`validator "${validatorName}" is not provided via NG_VALIDATORS`); + throw new Error(`validator "${validatorName}" is not provided via NG_VALIDATORS or NG_ASYNC_VALIDATORS`); } return Utils.isDefined(validatorArgs) ? validatorFn(validatorArgs) : validatorFn; } - getAsyncValidatorFn(asyncValidatorName: string, asyncValidatorArgs?: any): AsyncValidatorFn | never { + getValidators(config: DynamicValidatorsMap, + validatorFnsToken: any = this.NG_VALIDATORS): ValidatorFn[] | AsyncValidatorFn[] { - let asyncValidatorFn: Function | null = (Validators as any)[asyncValidatorName] || this.getCustomAsyncValidatorFn(asyncValidatorName); + let validatorFns: ValidatorFn[] | AsyncValidatorFn[] = []; - if (!Utils.isFunction(asyncValidatorFn)) { - throw new Error(`async validator "${asyncValidatorName}" is not provided via NG_ASYNC_VALIDATORS`); - } + if (Utils.isDefined(config)) { - return Utils.isDefined(asyncValidatorArgs) ? asyncValidatorFn(asyncValidatorArgs) : asyncValidatorFn; - } + validatorFns = Object.keys(config).map(key => { + let value = config[key], + validatorName, + validatorArgs; - getValidators(config: DynamicValidatorsMap): ValidatorFn[] { + if (Utils.isValidatorConfig(value)) { - return Utils.isDefined(config) ? - Object.keys(config).map(validatorName => this.getValidatorFn(validatorName, config[validatorName])) : []; - } + validatorName = (value as DynamicValidatorConfig).name; + validatorArgs = (value as DynamicValidatorConfig).args; + + } else { - getAsyncValidators(config: DynamicValidatorsMap): AsyncValidatorFn[] { + validatorName = key; + validatorArgs = value; + } - return Utils.isDefined(config) ? Object.keys(config).map( - asyncValidatorName => this.getAsyncValidatorFn(asyncValidatorName, config[asyncValidatorName])) : []; - } + return this.getValidatorFn(validatorName, validatorArgs, validatorFnsToken); + }); + } + return validatorFns; + } createFormArray(model: DynamicFormArrayModel): FormArray { @@ -140,8 +129,8 @@ export class DynamicFormService { return this.formBuilder.array( formArray, - this.getValidators(model.validator)[0] || null, - this.getAsyncValidators(model.asyncValidator)[0] || null + this.getValidators(model.validator)[0] as ValidatorFn || null, + this.getValidators(model.asyncValidator)[0] as AsyncValidatorFn || null ); } @@ -162,8 +151,8 @@ export class DynamicFormService { let groupModel = model as DynamicFormGroupModel, groupExtra = { - validator: this.getValidators(groupModel.validator)[0] || null, - asyncValidator: this.getValidators(groupModel.asyncValidator)[0] || null + validator: this.getValidators(groupModel.validator)[0] as ValidatorFn || null, + asyncValidator: this.getValidators(groupModel.asyncValidator)[0] as AsyncValidatorFn || null }; formGroup[model.id] = this.createFormGroup(groupModel.group, groupExtra); @@ -177,8 +166,8 @@ export class DynamicFormService { value: controlModel.value, disabled: controlModel.disabled }, - Validators.compose(this.getValidators(controlModel.validators || [])), - Validators.composeAsync(this.getAsyncValidators(controlModel.asyncValidators || [])) + Validators.compose(this.getValidators(controlModel.validators) as ValidatorFn[]), + Validators.composeAsync(this.getValidators(controlModel.asyncValidators, this.NG_ASYNC_VALIDATORS) as AsyncValidatorFn[]) ); } });