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..c4f047aa0 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_MODEL_CONFIG_MAP_FN, DynamicFormControlModelConfigMapFn, DynamicFormService } 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"; @@ -35,6 +35,21 @@ describe("DynamicFormService test suite", () => { let testModel: DynamicFormModel, service: DynamicFormService; + const DYNAMIC_FORM_CONTROL_TYPE_CUSTOM = "CUSTOM"; + + class DynamicCustomModel extends DynamicInputModel { + readonly type = DYNAMIC_FORM_CONTROL_TYPE_CUSTOM; + } + + const dynamicFormControlModelConfigMapFn: DynamicFormControlModelConfigMapFn = (model, layout, formService) => { + switch (model.type) { + case DYNAMIC_FORM_CONTROL_TYPE_CUSTOM: + return new DynamicCustomModel(model, layout); + default: + return null; + } + } + function testValidator() { return {testValidator: {valid: true}}; } @@ -50,6 +65,7 @@ describe("DynamicFormService test suite", () => { providers: [ DynamicFormService, DynamicFormValidationService, + {provide: DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN, useValue: dynamicFormControlModelConfigMapFn}, {provide: NG_VALIDATORS, useValue: testValidator, multi: true}, {provide: NG_ASYNC_VALIDATORS, useValue: testAsyncValidator, multi: true} ] @@ -220,6 +236,17 @@ describe("DynamicFormService test suite", () => { }); + it("should parse dynamic custom control JSON", () => { + const model = { id: 'custom', type: DYNAMIC_FORM_CONTROL_TYPE_CUSTOM }, + unknownModel = { id: 'unknownType', type: "UNKNOWN" }, + json = JSON.stringify([model]), + formModel = service.fromJSON(json); + + expect(formModel[0] instanceof DynamicCustomModel).toBe(true); + expect(service.getCustomComponentModel(model, null)).toBeDefined(); + expect(service.getCustomComponentModel(unknownModel, null)).toBeNull(); + }); + 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..4f7497d62 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"; @@ -46,14 +46,24 @@ 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 } from "../utils/json.utils"; -import { isString } from "../utils/core.utils"; +import { isFunction, isString } from '../utils/core.utils'; + +export type DynamicFormControlModelConfigMapFn = (model: any, layout: any, formService: DynamicFormService) => DynamicFormControlModel | null; +export const DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN = new InjectionToken( + 'DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN' +); @Injectable({ providedIn: "root" }) export class DynamicFormService { - constructor(private validationService: DynamicFormValidationService) {} + constructor(private validationService: DynamicFormValidationService, + @Inject(DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN) @Optional() + private readonly DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN: any, + ) { + this.DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN = DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN as DynamicFormControlModelConfigMapFn; + } private createAbstractControlOptions(validatorsConfig: DynamicValidatorsConfig | null = null, @@ -323,6 +333,12 @@ export class DynamicFormService { formModelJSON.forEach((model: any) => { let layout = model.layout || null; + let customModel = this.getCustomComponentModel(model, layout); + + if (customModel) { + formModel.push(customModel); + return; + } switch (model.type) { @@ -421,4 +437,10 @@ export class DynamicFormService { return formModel; } + + getCustomComponentModel(model: object, layout: any): DynamicFormControlModel | null { + return isFunction(this.DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN) + ? this.DYNAMIC_FORM_CONTROL_MODEL_CONFIG_MAP_FN(model, layout, this) + : null; + } }