diff --git a/src/conditionProcessValue.ts b/src/conditionProcessValue.ts index f16e0c1b40..e10fa2f9f4 100644 --- a/src/conditionProcessValue.ts +++ b/src/conditionProcessValue.ts @@ -150,7 +150,20 @@ export class ProcessValue { return res; } private getNonNestedObject(obj: any, text: string, createPath: boolean): any { - var curName = this.getFirstPropertyName(text, obj, createPath); + const checkedKeys = new Array(); + let len = 0; + let res = this.getNonNestedObjectCore(obj, text, createPath, checkedKeys); + while(!res && len < checkedKeys.length) { + len = checkedKeys.length; + res = this.getNonNestedObjectCore(obj, text, createPath, checkedKeys); + } + return res; + } + private getNonNestedObjectCore(obj: any, text: string, createPath: boolean, checkedKeys: Array): any { + var curName = this.getFirstPropertyName(text, obj, createPath, checkedKeys); + if(!!curName) { + checkedKeys.push(curName); + } var path = !!curName ? [curName] : null; while (text != curName && !!obj) { var isArray = text[0] == "["; @@ -170,7 +183,7 @@ export class ProcessValue { if (!!text && text[0] == ".") { text = text.substring(1); } - curName = this.getFirstPropertyName(text, obj, createPath); + curName = this.getFirstPropertyName(text, obj, createPath, checkedKeys); if (!!curName) { path.push(curName); } @@ -190,11 +203,7 @@ export class ProcessValue { if (index < 0 || index >= curValue.length) return null; return { value: curValue[index], text: text, index: index }; } - private getFirstPropertyName( - name: string, - obj: any, - createProp: boolean = false - ): string { + private getFirstPropertyName(name: string, obj: any, createProp: boolean = false, checkedKeys: Array = undefined): string { if (!name) return name; if (!obj) obj = {}; if (obj.hasOwnProperty(name)) return name; @@ -202,6 +211,7 @@ export class ProcessValue { var A = nameInLow[0]; var a = A.toUpperCase(); for (var key in obj) { + if(Array.isArray(checkedKeys) && checkedKeys.indexOf(key) > -1) continue; var first = key[0]; if (first === a || first === A) { var keyName = key.toLowerCase(); diff --git a/tests/surveytests.ts b/tests/surveytests.ts index a8b4707c65..29914a19b1 100644 --- a/tests/surveytests.ts +++ b/tests/surveytests.ts @@ -18183,4 +18183,34 @@ QUnit.test("Bug on loading json with collapsed panel. It was fixed in v1.9.117, panel.expand(); assert.equal(panel.isCollapsed, false, "panel is not collapsed"); }); - +QUnit.test("Expression bug with complex path, #7396", function (assert) { + const survey = new SurveyModel({ + elements: [ + { + type: "matrix", + name: "Q1.1", + columns: [1, 2], + rows: [1, 2, 3] + }, + { + type: "matrix", + name: "Q1.1.16", + columns: [1, 2, 3], + rows: ["16"] + }, + { + type: "text", + name: "Q1.1.16.A", + visibleIf: "{Q1.1.16.16} anyof [1, 2, 3]" + } + ] + }); + const q1 = survey.getQuestionByName("Q1.1"); + const q2 = survey.getQuestionByName("Q1.1.16"); + const q3 = survey.getQuestionByName("Q1.1.16.A"); + assert.equal(q3.isVisible, false, "visible #1"); + q1.value = { "1": 1, "2": 2 }; + assert.equal(q3.isVisible, false, "visible #2"); + q2.value = { "16": 2 }; + assert.equal(q3.isVisible, true, "visible #3"); +}); diff --git a/tests/textPreprocessorTests.ts b/tests/textPreprocessorTests.ts index 85d33ed1de..faaa5c0d93 100644 --- a/tests/textPreprocessorTests.ts +++ b/tests/textPreprocessorTests.ts @@ -154,7 +154,7 @@ QUnit.test("ProcessValue setValue function - create path", function (assert) { processor.setValue(data, "a[0].name", 1); assert.deepEqual( data, - { a: { b: 1 }, b: 1, c: { a: { b: 2 } } }, + { a: { b: 1 }, "a[0]": { "name": 1 }, b: 1, c: { a: { b: 2 } } }, "create new object" ); data = { a: { Item1: { c1: 0 }, Item3: { c1: 1 } } };