From 9bde0841debca4587d9decc9cee2b17453d51a06 Mon Sep 17 00:00:00 2001 From: Ron Netzer Date: Sat, 17 Aug 2019 21:13:22 +0300 Subject: [PATCH 1/5] feat(core): support transforming config before model creation --- .../lib/service/dynamic-form.service.spec.ts | 29 +++++++++++++++++-- .../src/lib/service/dynamic-form.service.ts | 26 +++++++++++++---- .../core/src/lib/utils/json.utils.spec.ts | 12 +++++++- .../core/src/lib/utils/json.utils.ts | 4 +++ 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts index 664f5dd7a..f37680b26 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts @@ -7,7 +7,7 @@ import { NG_VALIDATORS, NG_ASYNC_VALIDATORS } from "@angular/forms"; -import { DynamicFormService } from "./dynamic-form.service"; +import { DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN, DynamicFormService, ModelJSONTransformFn } from './dynamic-form.service'; import { DynamicFormValidationService } from "./dynamic-form-validation.service"; import { DynamicFormModel } from "../model/dynamic-form.model"; import { DynamicCheckboxModel } from "../model/checkbox/dynamic-checkbox.model"; @@ -192,7 +192,6 @@ describe("DynamicFormService test suite", () => { expect(formGroup.get("testColorPicker") instanceof FormControl).toBe(true); }); - it("should parse dynamic form JSON", () => { let json = JSON.stringify(testModel), @@ -220,6 +219,32 @@ describe("DynamicFormService test suite", () => { }); + it("should transform dynamic form control JSON", () => { + const addSuffixIfRequired: (suffix: string) => ModelJSONTransformFn = (suffix: string) => (jsonModel) => { + if (jsonModel.validators && jsonModel.validators.required === null) { + jsonModel.name = `${jsonModel.name}${suffix}`; + } + return jsonModel; + }, + model = new DynamicInputModel({ + id: 'test', + name: 'test', + validators: { required: null } + }); + + TestBed.overrideProvider(DynamicFormService, + { deps: [{ + provide: DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN, + useValue: [addSuffixIfRequired('*')] + }]}); + + inject([DynamicFormService], (formService) => { + expect(formService.getCustomJSONTransformer(model)).toBeDefined(); + expect(formService.getCustomJSONTransformer(model)).toEqual(jasmine.objectContaining({ name: 'test*' })); + }); + }); + + it("should throw when unknown DynamicFormControlModel id is specified in JSON", () => { expect(() => service.fromJSON([{id: "test"}])) diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts index 1aee7bce2..877bb4daf 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@angular/core"; +import { Inject, Injectable, InjectionToken, Optional } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup } from "@angular/forms"; import { AbstractControlOptions } from "@angular/forms"; import { DynamicFormControlModel, FormHooks } from "../model/dynamic-form-control.model"; @@ -45,15 +45,25 @@ import { DynamicFormValidationService } from "./dynamic-form-validation.service" import { DynamicFormModel, DynamicUnionFormModel } from "../model/dynamic-form.model"; import { DynamicPathable } from "../model/misc/dynamic-form-control-path.model"; import { DynamicValidatorsConfig } from "../model/misc/dynamic-form-control-validation.model"; -import { maskFromString, parseReviver } from "../utils/json.utils"; -import { isString } from "../utils/core.utils"; +import { maskFromString, parseReviver, pipe } from '../utils/json.utils'; +import { isFunction, isString } from '../utils/core.utils'; + +export type ModelJSONTransformFn = (modelJSON: T) => T; + +export type DynamicFormControlJSONTransformerMapFn = (modelJSON: T) => ModelJSONTransformFn[]; +export const DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN = new InjectionToken( + 'DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN' +); @Injectable({ providedIn: "root" }) export class DynamicFormService { - constructor(private validationService: DynamicFormValidationService) {} + constructor(private validationService: DynamicFormValidationService, + @Inject(DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN) @Optional() private readonly DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN: any) { + this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN = DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN as DynamicFormControlJSONTransformerMapFn; + } private createAbstractControlOptions(validatorsConfig: DynamicValidatorsConfig | null = null, @@ -321,7 +331,7 @@ export class DynamicFormService { formModel: DynamicFormModel = []; formModelJSON.forEach((model: any) => { - + model = this.getCustomJSONTransformer(model); let layout = model.layout || null; switch (model.type) { @@ -421,4 +431,10 @@ export class DynamicFormService { return formModel; } + + getCustomJSONTransformer(model: object): object { + return isFunction(this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN) + ? pipe(...this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN)(model) + : model; + } } diff --git a/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts b/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts index 7f2399c7f..8f05537f6 100644 --- a/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts +++ b/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts @@ -1,4 +1,4 @@ -import { maskFromString, maskToString, parseReviver } from "./json.utils"; +import { maskFromString, maskToString, parseReviver, pipe } from './json.utils'; describe("JSON utils test suite", () => { @@ -40,4 +40,14 @@ describe("JSON utils test suite", () => { expect(parseReviver("test", testValue1)).toEqual(new Date(testValue1)); }); + + it("should pass object in multiple functions", () => { + const object = { id: 'test' }, + transformer = (modifier: string) => (x: any) => { + x.id = `${x.id}${modifier}`; + return x; + }; + + expect(pipe(transformer('1'), transformer('2'))(object)).toEqual(jasmine.objectContaining({ id: 'test12' })); + }); }); diff --git a/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.ts b/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.ts index 85cc708d6..32dfa70d6 100644 --- a/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.ts +++ b/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.ts @@ -40,3 +40,7 @@ export function parseReviver(_key: string, value: any): any { return isString(value) && regexDateISO.test(value) ? new Date(value) : value; } + +export function pipe(...fns: ((x: T) => T)[]): (x: T) => T { + return x => fns.reduce((v, f) => f(v), x); +} From 10389d58aa4119c9cfdc615be4a1f480fa2183a6 Mon Sep 17 00:00:00 2001 From: Ron Netzer Date: Sat, 17 Aug 2019 22:00:16 +0300 Subject: [PATCH 2/5] refactor(core): change token name of JSON transform functions --- .../lib/service/dynamic-form.service.spec.ts | 24 ++++++++++++------- .../src/lib/service/dynamic-form.service.ts | 18 +++++++------- .../core/src/lib/utils/json.utils.spec.ts | 4 ++-- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts index f37680b26..9a85e74aa 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts @@ -7,7 +7,12 @@ import { NG_VALIDATORS, NG_ASYNC_VALIDATORS } from "@angular/forms"; -import { DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN, DynamicFormService, ModelJSONTransformFn } from './dynamic-form.service'; +import { + DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY, + DynamicFormControlJSONTransformFnArray, + DynamicFormService, + ModelJSONTransformFn +} from './dynamic-form.service'; import { DynamicFormValidationService } from "./dynamic-form-validation.service"; import { DynamicFormModel } from "../model/dynamic-form.model"; import { DynamicCheckboxModel } from "../model/checkbox/dynamic-checkbox.model"; @@ -220,27 +225,28 @@ describe("DynamicFormService test suite", () => { it("should transform dynamic form control JSON", () => { - const addSuffixIfRequired: (suffix: string) => ModelJSONTransformFn = (suffix: string) => (jsonModel) => { + const addLabelSuffixIfRequired: (suffix: string) => ModelJSONTransformFn = (suffix: string) => (jsonModel) => { if (jsonModel.validators && jsonModel.validators.required === null) { - jsonModel.name = `${jsonModel.name}${suffix}`; + jsonModel.label = `${jsonModel.label}${suffix}`; } return jsonModel; }, model = new DynamicInputModel({ - id: 'test', - name: 'test', + id: 'name', + name: 'name', + label: 'Name', validators: { required: null } }); TestBed.overrideProvider(DynamicFormService, { deps: [{ - provide: DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN, - useValue: [addSuffixIfRequired('*')] + provide: DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY, + useValue: [addLabelSuffixIfRequired('*')] as DynamicFormControlJSONTransformFnArray }]}); inject([DynamicFormService], (formService) => { - expect(formService.getCustomJSONTransformer(model)).toBeDefined(); - expect(formService.getCustomJSONTransformer(model)).toEqual(jasmine.objectContaining({ name: 'test*' })); + expect(formService.getCustomJSONTransform(model)).toBeDefined(); + expect(formService.getCustomJSONTransform(model)).toEqual(jasmine.objectContaining({ labell: 'Name*' })); }); }); diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts index 877bb4daf..96367f9f6 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts @@ -50,9 +50,9 @@ import { isFunction, isString } from '../utils/core.utils'; export type ModelJSONTransformFn = (modelJSON: T) => T; -export type DynamicFormControlJSONTransformerMapFn = (modelJSON: T) => ModelJSONTransformFn[]; -export const DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN = new InjectionToken( - 'DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN' +export type DynamicFormControlJSONTransformFnArray = ModelJSONTransformFn[]; +export const DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY = new InjectionToken( + 'DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY' ); @Injectable({ @@ -61,8 +61,8 @@ export const DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN = new InjectionToken { - model = this.getCustomJSONTransformer(model); + model = this.getCustomJSONTransform(model); let layout = model.layout || null; switch (model.type) { @@ -432,9 +432,9 @@ export class DynamicFormService { return formModel; } - getCustomJSONTransformer(model: object): object { - return isFunction(this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN) - ? pipe(...this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORMER_MAP_FN)(model) + getCustomJSONTransform(model: object): object { + return isFunction(this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY) + ? pipe(...this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY)(model) : model; } } diff --git a/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts b/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts index 8f05537f6..9968aaf57 100644 --- a/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts +++ b/projects/ng-dynamic-forms/core/src/lib/utils/json.utils.spec.ts @@ -43,11 +43,11 @@ describe("JSON utils test suite", () => { it("should pass object in multiple functions", () => { const object = { id: 'test' }, - transformer = (modifier: string) => (x: any) => { + modifyId = (modifier: string) => (x: any) => { x.id = `${x.id}${modifier}`; return x; }; - expect(pipe(transformer('1'), transformer('2'))(object)).toEqual(jasmine.objectContaining({ id: 'test12' })); + expect(pipe(modifyId('1'), modifyId('2'))(object)).toEqual(jasmine.objectContaining({ id: 'test12' })); }); }); From 65d40a87df2c4c400fe09bcb3d9c632e0abd9d05 Mon Sep 17 00:00:00 2001 From: Ron Netzer Date: Sat, 17 Aug 2019 22:53:35 +0300 Subject: [PATCH 3/5] test(core): improve dynamicFormService coverage --- .../lib/service/dynamic-form.service.spec.ts | 21 +++++++------------ .../src/lib/service/dynamic-form.service.ts | 3 ++- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts index 9a85e74aa..cd6d77ea9 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts @@ -225,28 +225,21 @@ describe("DynamicFormService test suite", () => { it("should transform dynamic form control JSON", () => { - const addLabelSuffixIfRequired: (suffix: string) => ModelJSONTransformFn = (suffix: string) => (jsonModel) => { - if (jsonModel.validators && jsonModel.validators.required === null) { - jsonModel.label = `${jsonModel.label}${suffix}`; - } + const addLabelSuffix: (suffix: string) => ModelJSONTransformFn = (suffix: string) => (jsonModel) => { + jsonModel.label = `${jsonModel.label}${suffix}`; return jsonModel; - }, - model = new DynamicInputModel({ - id: 'name', - name: 'name', - label: 'Name', - validators: { required: null } - }); + } TestBed.overrideProvider(DynamicFormService, { deps: [{ provide: DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY, - useValue: [addLabelSuffixIfRequired('*')] as DynamicFormControlJSONTransformFnArray + useValue: [addLabelSuffix('*')] as DynamicFormControlJSONTransformFnArray }]}); inject([DynamicFormService], (formService) => { - expect(formService.getCustomJSONTransform(model)).toBeDefined(); - expect(formService.getCustomJSONTransform(model)).toEqual(jasmine.objectContaining({ labell: 'Name*' })); + const json = JSON.stringify([new DynamicInputModel({ id: 'name', label: 'Name' })]), + formModel = formService.fromJSON(json); + expect(formModel[0]).toEqual(jasmine.objectContaining({ labell: 'Name*' })); }); }); diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts index 96367f9f6..b69b1296d 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts @@ -61,7 +61,8 @@ export const DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY = new InjectionToken Date: Tue, 20 Aug 2019 11:32:37 +0300 Subject: [PATCH 4/5] fix(core): check if JSON transform is array and not func also trying to improve coverage --- .../lib/service/dynamic-form.service.spec.ts | 26 +++++++------------ .../src/lib/service/dynamic-form.service.ts | 2 +- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts index cd6d77ea9..aee69dba0 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts @@ -36,6 +36,10 @@ import { DynamicTimePickerModel } from "../model/timepicker/dynamic-timepicker.m import { DynamicFormValueControlModel } from "../model/dynamic-form-value-control.model"; describe("DynamicFormService test suite", () => { + const labelSuffixTranformer: (suffix: string) => ModelJSONTransformFn = (suffix: string) => (jsonModel) => { + jsonModel.label = `${jsonModel.label}${suffix}`; + return jsonModel; + }; let testModel: DynamicFormModel, service: DynamicFormService; @@ -55,6 +59,7 @@ describe("DynamicFormService test suite", () => { providers: [ DynamicFormService, DynamicFormValidationService, + {provide: DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY, useValue: [labelSuffixTranformer('*')]}, {provide: NG_VALIDATORS, useValue: testValidator, multi: true}, {provide: NG_ASYNC_VALIDATORS, useValue: testAsyncValidator, multi: true} ] @@ -225,22 +230,11 @@ describe("DynamicFormService test suite", () => { it("should transform dynamic form control JSON", () => { - const addLabelSuffix: (suffix: string) => ModelJSONTransformFn = (suffix: string) => (jsonModel) => { - jsonModel.label = `${jsonModel.label}${suffix}`; - return jsonModel; - } - - TestBed.overrideProvider(DynamicFormService, - { deps: [{ - provide: DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY, - useValue: [addLabelSuffix('*')] as DynamicFormControlJSONTransformFnArray - }]}); - - inject([DynamicFormService], (formService) => { - const json = JSON.stringify([new DynamicInputModel({ id: 'name', label: 'Name' })]), - formModel = formService.fromJSON(json); - expect(formModel[0]).toEqual(jasmine.objectContaining({ labell: 'Name*' })); - }); + const model = new DynamicInputModel({ id: 'name', label: 'Name' }), + json = JSON.stringify([model]), + formModel = service.fromJSON(json); + expect(formModel[0]).toEqual(jasmine.objectContaining({ label: 'Name*' })); + expect(service.getCustomJSONTransform(model)).toEqual(jasmine.objectContaining({ label: 'Name*' })); }); diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts index b69b1296d..4f4423620 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts @@ -434,7 +434,7 @@ export class DynamicFormService { } getCustomJSONTransform(model: object): object { - return isFunction(this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY) + return Array.isArray(this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY) ? pipe(...this.DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY)(model) : model; } From 80b4300a78199c7b0776391e30d84f099d1c02e3 Mon Sep 17 00:00:00 2001 From: Ron Netzer Date: Tue, 20 Aug 2019 11:35:07 +0300 Subject: [PATCH 5/5] refactor(core): remove unused imports --- .../core/src/lib/service/dynamic-form.service.spec.ts | 1 - .../core/src/lib/service/dynamic-form.service.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts index aee69dba0..99dae0ec7 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.spec.ts @@ -9,7 +9,6 @@ import { } from "@angular/forms"; import { DYNAMIC_FORM_CONTROL_JSON_TRANSFORM_FN_ARRAY, - DynamicFormControlJSONTransformFnArray, DynamicFormService, ModelJSONTransformFn } from './dynamic-form.service'; diff --git a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts index 4f4423620..d6a31249d 100644 --- a/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts +++ b/projects/ng-dynamic-forms/core/src/lib/service/dynamic-form.service.ts @@ -46,7 +46,7 @@ import { DynamicFormModel, DynamicUnionFormModel } from "../model/dynamic-form.m import { DynamicPathable } from "../model/misc/dynamic-form-control-path.model"; import { DynamicValidatorsConfig } from "../model/misc/dynamic-form-control-validation.model"; import { maskFromString, parseReviver, pipe } from '../utils/json.utils'; -import { isFunction, isString } from '../utils/core.utils'; +import { isString } from '../utils/core.utils'; export type ModelJSONTransformFn = (modelJSON: T) => T;