Skip to content

Commit

Permalink
Validators processing refactored (#424)
Browse files Browse the repository at this point in the history
  • Loading branch information
udos86 committed Jul 1, 2017
1 parent 7c92538 commit 84b1f4d
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 63 deletions.
6 changes: 5 additions & 1 deletion example/app/basic/basic-example.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
DynamicFormArrayModel,
DynamicFormGroupModel
} from "@ng2-dynamic-forms/core";
import { customValidator } from "../app.module";

export const BASIC_EXAMPLE_MODEL = [

Expand Down Expand Up @@ -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",
Expand Down
13 changes: 13 additions & 0 deletions modules/core/src/core.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand Down
8 changes: 7 additions & 1 deletion modules/core/src/model/dynamic-form-control.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down
16 changes: 5 additions & 11 deletions modules/core/src/service/dynamic-form.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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`));
});
});
89 changes: 39 additions & 50 deletions modules/core/src/service/dynamic-form.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {

Expand All @@ -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
);
}

Expand All @@ -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);
Expand All @@ -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[])
);
}
});
Expand Down

0 comments on commit 84b1f4d

Please sign in to comment.