From 8f3a287edf82e875d231a5e4ff82f3f37577ffb9 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 29 Jul 2024 22:22:43 +0300 Subject: [PATCH] Load values order from JSON based on depends on property fix #8624 (#8626) * Load values order from JSON based on depends on property fix #8624 * Small refactoring #8624 --- src/jsonobject.ts | 54 +++++++++++++++++++++++-------------- src/question_text.ts | 2 +- tests/jsonobjecttests.ts | 16 +++++++++++ tests/question_texttests.ts | 20 ++++++++++++++ 4 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/jsonobject.ts b/src/jsonobject.ts index 1f15a949c1..cd876888e3 100644 --- a/src/jsonobject.ts +++ b/src/jsonobject.ts @@ -337,7 +337,7 @@ export class JsonObjectProperty implements IObject, IJsonPropertyInfo { this.idValue = JsonObjectProperty.Index++; } uniqueProperty?: string; - dependsOn?: string | string[]; + dependsOn?: string | Array; default?: any; defaultFunc?: (obj: Base) => any; public get id(): number { @@ -1028,12 +1028,10 @@ export class JsonMetadataClass { return prop; } private addDependsOnProperties(prop: JsonObjectProperty, dependsOn: any) { - if (Array.isArray(dependsOn)) { - for (var i = 0; i < dependsOn.length; i++) { - this.addDependsOnProperty(prop, dependsOn[i]); - } - } else { - this.addDependsOnProperty(prop, dependsOn); + const dArray = Array.isArray(dependsOn) ? dependsOn : [dependsOn]; + prop.dependsOn = dArray; + for (var i = 0; i < dArray.length; i++) { + this.addDependsOnProperty(prop, dArray[i]); } } private addDependsOnProperty(prop: JsonObjectProperty, dependsOn: string) { @@ -1689,26 +1687,42 @@ export class JsonObject { } properties = this.addDynamicProperties(obj, jsonObj, properties); this.options = options; + const processedProps: any = {}; + processedProps[JsonObject.typePropertyName] = true; + const parentProps = {}; for (var key in jsonObj) { - if (key === JsonObject.typePropertyName) continue; - if (key === JsonObject.positionPropertyName) { - obj[key] = jsonObj[key]; - continue; - } - var property = this.findProperty(properties, key); - if (!property) { - if (needAddErrors) { - this.addNewError(new JsonUnknownPropertyError(key.toString(), objType), jsonObj, obj); - } - continue; - } - this.valueToObj(jsonObj[key], obj, property, jsonObj, options); + this.setPropertyValueToObj(jsonObj, obj, key, properties, processedProps, parentProps, objType, needAddErrors, options); } this.options = undefined; if (obj.endLoadingFromJson) { obj.endLoadingFromJson(); } } + private setPropertyValueToObj(jsonObj: any, obj: any, key: string, properties: Array, processedProps: any, parentProps: any, + objType: string, needAddErrors: boolean, options: ILoadFromJSONOptions): void { + if (processedProps[key]) return; + if (key === JsonObject.positionPropertyName) { + obj[key] = jsonObj[key]; + return; + } + const property = this.findProperty(properties, key); + if (!property && needAddErrors) { + this.addNewError(new JsonUnknownPropertyError(key.toString(), objType), jsonObj, obj); + } + if(property) { + const dProps = property.dependsOn; + if(Array.isArray(dProps)) { + parentProps[key] = true; + dProps.forEach(propKey => { + if(!parentProps[propKey]) { + this.setPropertyValueToObj(jsonObj, obj, propKey, properties, processedProps, parentProps, objType, needAddErrors, options); + } + }); + } + this.valueToObj(jsonObj[key], obj, property, jsonObj, options); + processedProps[key] = true; + } + } public toJsonObjectCore( obj: any, property: JsonObjectProperty, diff --git a/src/question_text.ts b/src/question_text.ts index cbb902e712..7864a8078d 100644 --- a/src/question_text.ts +++ b/src/question_text.ts @@ -816,7 +816,7 @@ Serializer.addClass( name: "maskSettings:masksettings", className: "masksettings", visibleIndex: 1, - dependsOn: "inputType", + dependsOn: ["inputType", "maskType"], visibleIf: (obj: any) => { return obj.inputType === "text" || obj.inputType === "tel"; }, diff --git a/tests/jsonobjecttests.ts b/tests/jsonobjecttests.ts index fa69e48b8b..4f429acfb0 100644 --- a/tests/jsonobjecttests.ts +++ b/tests/jsonobjecttests.ts @@ -3308,3 +3308,19 @@ QUnit.test("enableIf", function (assert) { Serializer.removeProperty("question", "testProperty3"); Serializer.removeProperty("question", "testProperty4"); }); +QUnit.test("circular dependsOn, #8624", function (assert) { + const prop1 = Serializer.addProperty("question", { name: "testProperty1" }); + Serializer.addProperty("question", { name: "testProperty2", dependsOn: "testProperty1" }); + prop1.dependsOn = ["testProperty2"]; + + const q: any = new Question("q1"); + q.fromJSON({ + testProperty1: "abc", + testProperty2: "edf" + }); + assert.equal(q.testProperty1, "abc", "testProperty1 value"); + assert.equal(q.testProperty2, "edf", "testProperty2 value"); + + Serializer.removeProperty("question", "testProperty1"); + Serializer.removeProperty("question", "testProperty2"); +}); diff --git a/tests/question_texttests.ts b/tests/question_texttests.ts index 1884c58ebb..0736b1a372 100644 --- a/tests/question_texttests.ts +++ b/tests/question_texttests.ts @@ -4,6 +4,7 @@ import { SurveyModel } from "../src/survey"; import { QuestionTextBase, CharacterCounter } from "../src/question_textbase"; import { settings } from "../src/settings"; import { StylesManager } from "../src/stylesmanager"; +import { InputMaskPattern } from "../src/mask/mask_pattern"; QUnit.test("check text disabled class", function (assert) { var json = { @@ -488,3 +489,22 @@ QUnit.test("inputType='date' invalid value, #8617", function(assert) { q1.value = "2000-01-01"; assert.equal(q1.errors.length, 0, "errors #5"); }); +QUnit.test("Mask is removed on loading, Bug#8624", function(assert) { + const survey = new SurveyModel({ + elements: [ + { + maskSettings: { + pattern: "999-99-999999", + saveMaskedValue: true, + }, + maskType: "pattern", + name: "q1", + type: "text" + }, + ] + }); + const q1 = survey.getQuestionByName("q1"); + const maskSettings = q1.maskSettings as InputMaskPattern; + assert.equal(q1.maskType, "pattern", "mask type is set correctly"); + assert.equal(maskSettings.pattern, "999-99-999999", "pattern is loaded"); +}); \ No newline at end of file