diff --git a/src/components/_classes/component/Component.js b/src/components/_classes/component/Component.js index e03c56d624..d0f1cb012d 100644 --- a/src/components/_classes/component/Component.js +++ b/src/components/_classes/component/Component.js @@ -2923,7 +2923,7 @@ export default class Component extends Element { if (fromSubmission) { // If we set value from submission and it differs from calculated one, set the calculated value to prevent overriding dataValue in the next pass - this.calculatedValue = calculatedValue; + this.calculatedValue = fastCloneDeep(calculatedValue); return false; } @@ -2934,7 +2934,7 @@ export default class Component extends Element { } } - this.calculatedValue = calculatedValue; + this.calculatedValue = fastCloneDeep(calculatedValue); if (changed) { if (!flags.noPristineChangeOnModified) { diff --git a/src/components/datagrid/DataGrid.js b/src/components/datagrid/DataGrid.js index beac6bd5f0..79832f80bc 100644 --- a/src/components/datagrid/DataGrid.js +++ b/src/components/datagrid/DataGrid.js @@ -147,6 +147,18 @@ export default class DataGridComponent extends NestedArrayComponent { })); } + isEmpty(value = this.dataValue) { + const isEmpty = super.isEmpty(value); + + if (this.components.length) { + return this.components.reduce((isEmpty, component) => { + return isEmpty && component.isEmpty(); + }, true); + } + + return isEmpty; + } + /** * Split rows into chunks. * @param {Number[]} groups - array of numbers where each item is size of group diff --git a/src/components/datagrid/DataGrid.unit.js b/src/components/datagrid/DataGrid.unit.js index 32aaf17c00..e563067abd 100644 --- a/src/components/datagrid/DataGrid.unit.js +++ b/src/components/datagrid/DataGrid.unit.js @@ -20,7 +20,8 @@ import { modalWithRequiredFields, withConditionalFieldsAndValidations, withLogic, - withCollapsibleRowGroups + withCollapsibleRowGroups, + withAllowCalculateOverride } from './fixtures'; describe('DataGrid Component', () => { @@ -501,3 +502,66 @@ describe('DataGrid modal', () => { .catch(done); }); }); + +describe('DataGrid calculated values', () => { + it('Should allow override calculated value', (done) => { + Formio.createForm(document.createElement('div'), withAllowCalculateOverride) + .then((form) => { + const select = form.getComponent('select'); + const dataGrid = form.getComponent('dataGrid'); + + assert.deepEqual(dataGrid.getValue(), + [{ + firstName: 'initial 1', + lastName: 'initial 2' + }, + { + firstName: 'initial 1b', + lastName: 'initial 2b' + }] + ); + + select.setValue('a', { modified: true }); + setTimeout(() => { + assert.deepEqual(dataGrid.getValue(), + [{ + firstName: 'A f 1', + lastName: 'A l 1' + }] + ); + + select.setValue('b', { modified: true }); + setTimeout(() => { + assert.deepEqual(dataGrid.getValue(), + [{ + firstName: 'B f 1', + lastName: 'B l 1' + }, + { + firstName: 'B f 2', + lastName: 'B l 2' + }] + ); + + const firstName = form.getComponent(['dataGrid', 0, 'firstName']); + firstName.setValue('first name', { modified: true }); + select.setValue('c', { modified: true }); + setTimeout(() => { + assert.deepEqual(dataGrid.getValue(), + [{ + firstName: 'first name', + lastName: 'B l 1' + }, + { + firstName: 'B f 2', + lastName: 'B l 2' + }] + ); + done(); + }, 300); + }, 300); + }, 300); + }) + .catch(done); + }); +}); diff --git a/src/components/datagrid/fixtures/comp-with-allow-calculate-override.js b/src/components/datagrid/fixtures/comp-with-allow-calculate-override.js new file mode 100644 index 0000000000..55a3e367ff --- /dev/null +++ b/src/components/datagrid/fixtures/comp-with-allow-calculate-override.js @@ -0,0 +1,66 @@ +export default { + type: 'form', + display: 'form', + components: [ + { + label: 'Select', + widget: 'choicesjs', + tableView: true, + data: { + values: [ + { + label: 'a', + value: 'a' + }, + { + label: 'b', + value: 'b' + }, + { + label: 'c', + value: 'c' + } + ] + }, + key: 'select', + type: 'select', + input: true + }, + { + label: 'Data Grid', + reorder: false, + addAnotherPosition: 'bottom', + layoutFixed: false, + enableRowGroups: false, + initEmpty: false, + tableView: false, + defaultValue: [ + { + firstName: '', + lastName: '' + } + ], + calculateValue: "var temp = [\n {'firstName': 'initial 1','lastName': 'initial 2'},\n {'firstName': 'initial 1b','lastName': 'initial 2b'},\n ];\n if(data.select === 'a')\n {\n temp = [{'firstName': 'A f 1','lastName': 'A l 1'}];\n } else if(data.select === 'b') { \n temp = [{'firstName': 'B f 1','lastName': 'B l 1'} \n ,{'firstName': 'B f 2','lastName': 'B l 2'}];\n } else if(data.select === 'c') { \n temp = [{'firstName': 'C f 1','lastName': 'C l 1'}];\n }\n value = temp;", + allowCalculateOverride: true, + key: 'dataGrid', + type: 'datagrid', + input: true, + components: [ + { + label: 'First Name', + tableView: true, + key: 'firstName', + type: 'textfield', + input: true + }, + { + label: 'Last Name', + tableView: true, + key: 'lastName', + type: 'textfield', + input: true + } + ] + } + ] +}; diff --git a/src/components/datagrid/fixtures/index.js b/src/components/datagrid/fixtures/index.js index 94c91b549b..417e0c136e 100644 --- a/src/components/datagrid/fixtures/index.js +++ b/src/components/datagrid/fixtures/index.js @@ -12,4 +12,5 @@ import modalWithRequiredFields from './comp-modal-with-required-fields'; import withConditionalFieldsAndValidations from './comp-with-conditional-components-and-validations'; import withLogic from './comp-with-logic'; import withCollapsibleRowGroups from './comp-with-collapsible-groups'; -export { comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, withCollapsibleRowGroups, withConditionalFieldsAndValidations, withDefValue, withLogic, withRowGroupsAndDefValue, modalWithRequiredFields }; +import withAllowCalculateOverride from './comp-with-allow-calculate-override'; +export { comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, withCollapsibleRowGroups, withConditionalFieldsAndValidations, withDefValue, withLogic, withRowGroupsAndDefValue, modalWithRequiredFields, withAllowCalculateOverride }; diff --git a/src/components/editgrid/EditGrid.js b/src/components/editgrid/EditGrid.js index ab7f464a0e..8594d1969c 100644 --- a/src/components/editgrid/EditGrid.js +++ b/src/components/editgrid/EditGrid.js @@ -673,6 +673,11 @@ export default class EditGridComponent extends NestedArrayComponent { : this.editRows.reduce((result, row) => result.concat(row.components || []), []); } + destroy(all = false) { + this.calculatedValue = undefined; + super.destroy(all); + } + destroyComponents(all = false, rowIndex = 0) { if (this.builderMode) { return super.destroyComponents(all); diff --git a/test/forms/helpers/testBasicComponentSettings/tests.js b/test/forms/helpers/testBasicComponentSettings/tests.js index 7c8aaed1ed..d3acf2b0aa 100644 --- a/test/forms/helpers/testBasicComponentSettings/tests.js +++ b/test/forms/helpers/testBasicComponentSettings/tests.js @@ -278,7 +278,7 @@ export default { done(); }, }, - + redrawOn: { 'Should redraw on checkbox value change'(form, done) { const checkboxValue = form.data.checkbox; @@ -492,7 +492,12 @@ export default { assert.deepEqual(!!confirmationDialogAfter, false, `${compKey} (component ${compType}): should close confirmation dialog`); if (!componentsWithBug.includes(compType)) { - assert.deepEqual(comp.getValue(), initialValue, `${compKey} (component ${compType}): should clear value in modalEdit mode`); + if (compType === 'form') { + assert.deepEqual(comp.getValue().data, initialValue.data, `${compKey} (component ${compType}): should clear value in modalEdit mode`); + } + else { + assert.deepEqual(comp.getValue(), initialValue, `${compKey} (component ${compType}): should clear value in modalEdit mode`); + } } assert.deepEqual(isModalWindowOpened(), false, `${compKey} (component ${compType}): should close modal window`);