diff --git a/src/question.ts b/src/question.ts index 05729bb8b8..3c473f86b3 100644 --- a/src/question.ts +++ b/src/question.ts @@ -1858,6 +1858,9 @@ export class Question extends SurveyElement if (this.isDesignMode && this.isContentElement && this.isDefaultValueEmpty()) return; this.setDefaultValue(); } + public get isValueDefault(): boolean { + return !this.isEmpty() && (this.isTwoValueEquals(this.defaultValue, this.value) || !this.isValueChangedDirectly && !!this.defaultValueExpression); + } protected get isClearValueOnHidden(): boolean { const clearIf = this.getClearIfInvisible(); if (clearIf === "none" || clearIf === "onComplete") return false; @@ -1931,8 +1934,8 @@ export class Question extends SurveyElement }); }; } - if (!values) values = this.data.getFilteredValues(); - if (!properties) properties = this.data.getFilteredProperties(); + if (!values) values = this.defaultValueExpression ? this.data.getFilteredValues() : {}; + if (!properties) properties = this.defaultValueExpression ? this.data.getFilteredProperties() : {}; if (!!runner && runner.canRun) { runner.onRunComplete = (res) => { if (res == undefined) res = this.defaultValue; diff --git a/src/question_matrixdropdown.ts b/src/question_matrixdropdown.ts index 4ab7d9a177..fbea291e10 100644 --- a/src/question_matrixdropdown.ts +++ b/src/question_matrixdropdown.ts @@ -146,6 +146,26 @@ export class QuestionMatrixDropdownModel extends QuestionMatrixDropdownModelBase super.clearValueIfInvisibleCore(reason); this.clearInvisibleValuesInRows(); } + private defaultValuesInRows: any = {}; + protected clearGeneratedRows(): void { + if (!this.generatedVisibleRows) return; + if(!this.isDisposed) { + this.generatedVisibleRows.forEach(row => { + this.defaultValuesInRows[row.rowName] = row.getNamesWithDefaultValues(); + }); + } + super.clearGeneratedRows(); + } + private getRowValueForCreation(val: any, rowValue: any): any { + const res = val[rowValue]; + if(!res) return res; + const names = this.defaultValuesInRows[rowValue]; + if(!Array.isArray(names) || names.length === 0) return res; + names.forEach(name => { + delete res[name]; + }); + return res; + } protected generateRows(): Array { var result = new Array(); var rows = !!this.filteredRows ? this.filteredRows : this.rows; @@ -153,8 +173,9 @@ export class QuestionMatrixDropdownModel extends QuestionMatrixDropdownModelBase var val = this.value; if (!val) val = {}; for (var i = 0; i < rows.length; i++) { - if (this.isValueEmpty(rows[i].value)) continue; - result.push(this.createMatrixRow(rows[i], val[rows[i].value])); + const row = rows[i]; + if (this.isValueEmpty(row.value)) continue; + result.push(this.createMatrixRow(row, this.getRowValueForCreation(val, row.value))); } return result; } diff --git a/src/question_matrixdropdownbase.ts b/src/question_matrixdropdownbase.ts index b2963257d4..2f0736b80b 100644 --- a/src/question_matrixdropdownbase.ts +++ b/src/question_matrixdropdownbase.ts @@ -385,18 +385,22 @@ export class MatrixDropdownRowModelBase implements ISurveyData, ISurveyImpl, ILo } } res.row = this.getAllValues(); + this.applyRowVariablesToValues(res, this.rowIndex); return res; } getFilteredProperties(): any { return { survey: this.getSurvey(), row: this }; } + private applyRowVariablesToValues(res: any, rowIndex: number): void { + res[MatrixDropdownRowModelBase.IndexVariableName] = rowIndex; + res[MatrixDropdownRowModelBase.RowValueVariableName] = this.rowName; + } public runCondition(values: HashTable, properties: HashTable): void { if (!!this.data) { values[MatrixDropdownRowModelBase.OwnerVariableName] = this.data.value; } const rowIndex = this.rowIndex; - values[MatrixDropdownRowModelBase.IndexVariableName] = rowIndex; - values[MatrixDropdownRowModelBase.RowValueVariableName] = this.rowName; + this.applyRowVariablesToValues(values, rowIndex); const newProps = Helpers.createCopy(properties); newProps[MatrixDropdownRowModelBase.RowVariableName] = this; const rowValues = rowIndex > 0 ? this.data.getRowValue(this.rowIndex - 1) : this.value; @@ -411,6 +415,15 @@ export class MatrixDropdownRowModelBase implements ISurveyData, ISurveyImpl, ILo this.detailPanel.runCondition(values, newProps); } } + public getNamesWithDefaultValues(): Array { + const res: Array = []; + this.questions.forEach(q => { + if(q.isValueDefault) { + res.push(q.getValueName()); + } + }); + return res; + } public clearValue(keepComment?: boolean): void { var questions = this.questions; for (var i = 0; i < questions.length; i++) { @@ -1154,7 +1167,7 @@ export class QuestionMatrixDropdownModelBase extends QuestionMatrixBaseModelsurvey.getQuestionByName("matrix"); + const question = survey.getQuestionByName("q1"); + assert.equal(matrix.visibleRows[0].cells[0].question.value, 5, "question value #1"); + question.value = 10; + const id = matrix.visibleRows[0].id; + assert.equal(matrix.visibleRows[0].cells[0].question.value, 10, "question value #2"); + matrix.addColumn("col2"); + assert.notEqual(matrix.visibleRows[0].id, id, "It is a new row"); + question.value = 15; + assert.equal(matrix.visibleRows[0].cells[0].question.value, 15, "question value #3"); +}); +QUnit.test("defaultValueExpression & using rowvalue in it", function (assert) { + const survey = new SurveyModel({ + elements: [ + { + type: "text", + name: "q1", + defaultValue: 5 + }, + { + type: "matrixdynamic", + name: "matrix", + rowCount: 1, + columns: [ + { + name: "col1", + cellType: "text", + defaultValueExpression: "{q1}" + } + ] + } + ] + }); + const matrix = survey.getQuestionByName("matrix"); + const question = survey.getQuestionByName("q1"); + assert.equal(matrix.visibleRows[0].cells[0].question.value, 5, "question value #1"); + question.value = 10; + const id = matrix.visibleRows[0].id; + assert.equal(matrix.visibleRows[0].cells[0].question.value, 10, "question value #2"); + matrix.addColumn("col2"); + assert.notEqual(matrix.visibleRows[0].id, id, "It is a new row"); + question.value = 15; + assert.equal(matrix.visibleRows[0].cells[0].question.value, 15, "question value #3"); +}); +QUnit.test("defaultValueExpression & using rowvalue in it", function (assert) { + const survey = new SurveyModel({ + elements: [ + { + type: "text", + name: "q1", + defaultValue: 5 + }, + { + type: "text", + name: "q2", + defaultValue: 10 + }, + { + type: "matrixdropdown", + name: "matrix", + columns: [ + { + name: "col1", + cellType: "text", + defaultValueExpression: "iif({rowvalue} = 'row1', {q1}, iif({rowvalue} = 'row2', {q2}))" + }, + { name: "col2", cellType: "text" } + ], + rows: [ + { value: "row1", visibleIf: "{q1} > 1" }, + { value: "row2", visibleIf: "{q2} > 1" }] + } + ] + }); + const matrix = survey.getQuestionByName("matrix"); + const q1 = survey.getQuestionByName("q1"); + const q2 = survey.getQuestionByName("q2"); + assert.equal(matrix.visibleRows[0].cells[0].question.value, 5, "cell1 value #1"); + assert.equal(matrix.visibleRows[1].cells[0].question.value, 10, "cell1 value #1"); + matrix.visibleRows[0].cells[1].question.value = 12; + q1.value = 15; + q2.value = 20; + assert.equal(matrix.visibleRows[0].cells[0].question.value, 15, "cell1 value #2"); + assert.equal(matrix.visibleRows[1].cells[0].question.value, 20, "cell1 value #2"); + q1.value = 0; + assert.equal(matrix.visibleRows.length, 1, "visible rows count #1"); + const id = matrix.visibleRows[0].id; + q1.value = 30; + q2.value = 50; + assert.notEqual(matrix.visibleRows[0].id, id, "It is a new row"); + assert.equal(matrix.visibleRows.length, 2, "visible rows count #2"); + assert.equal(matrix.visibleRows[0].cells[1].question.value, 12, "Keep value in the standard cell"); + assert.equal(matrix.visibleRows[0].cells[0].question.value, 30, "cell1 value #3"); + assert.equal(matrix.visibleRows[1].cells[0].question.value, 50, "cell1 value #3"); +}); \ No newline at end of file diff --git a/tests/surveyquestiontests.ts b/tests/surveyquestiontests.ts index 2e84a80a54..0e654302b1 100644 --- a/tests/surveyquestiontests.ts +++ b/tests/surveyquestiontests.ts @@ -7781,3 +7781,37 @@ QUnit.test("QuestionImagePickerModel.needResponsiveWidth", function (assert) { q.colCount = 3; assert.equal(q.needResponsiveWidth(), true, "Responsive in auto mode for several columns"); }); +QUnit.test("question.isDefaultValue", function (assert) { + const survey = new SurveyModel({ + elements: [ + { name: "q1", type: "text", defaultValue: 1 }, + { name: "q2", type: "text", defaultValueExpression: "1 + 1" }, + { name: "q3", type: "text", defaultValueExpression: "{q1} + {q2}" }, + { name: "q4", type: "text" } + ] + }); + const q1 = survey.getQuestionByName("q1"); + const q2 = survey.getQuestionByName("q2"); + const q3 = survey.getQuestionByName("q3"); + const q4 = survey.getQuestionByName("q4"); + assert.equal(q1.value, 1, "q1 value is 1"); + assert.equal(q1.isValueDefault, true, "q1 #1"); + assert.equal(q2.isValueDefault, true, "q2 #1"); + assert.equal(q3.isValueDefault, true, "q3 #1"); + assert.equal(q4.isValueDefault, false, "q4 #1"); + q1.value = ""; + assert.equal(q1.isValueDefault, false, "q1 #2"); + assert.equal(q2.isValueDefault, true, "q2 #2"); + assert.equal(q3.isValueDefault, true, "q3 #2"); + assert.equal(q4.isValueDefault, false, "q4 #2"); + q2.value = 4; + assert.equal(q1.isValueDefault, false, "q1 #3"); + assert.equal(q2.isValueDefault, false, "q2 #3"); + assert.equal(q3.isValueDefault, true, "q3 #3"); + assert.equal(q4.isValueDefault, false, "q4 #3"); + q3.value = 10; + assert.equal(q1.isValueDefault, false, "q1 #4"); + assert.equal(q2.isValueDefault, false, "q2 #4"); + assert.equal(q3.isValueDefault, false, "q3 #4"); + assert.equal(q4.isValueDefault, false, "q4 #4"); +});