diff --git a/Changelog.md b/Changelog.md index 6b774f7ff5..bf496bc168 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,9 +4,13 @@ All notable changes to this project will be documented in this file The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased: 5.0.0-rc.95] +## 5.0.0-rc.95 ### Changed + - Updated @formio/core@2.3.0-rc.17 + - FIO-9205: fixed an issue where Select Filter feature does not work - FIO-9173: Allow Scientific Notations + - FIO-9247 fixed triggering custom validation inside Edit Grid + ## 5.0.0-rc.94 ### Changed diff --git a/package.json b/package.json index 2f1a3cc93b..d6541b1075 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@formio/js", - "version": "5.0.0-rc.94", + "version": "5.0.0-rc.95", "description": "JavaScript powered Forms with JSON Form Builder", "main": "lib/cjs/index.js", "exports": { @@ -81,7 +81,7 @@ "dependencies": { "@formio/bootstrap": "3.0.0-rc.41", "@formio/choices.js": "^10.2.1", - "@formio/core": "2.3.0-rc.16", + "@formio/core": "2.3.0-rc.17", "@formio/text-mask-addons": "^3.8.0-formio.3", "@formio/vanilla-text-mask": "^5.1.1-formio.1", "abortcontroller-polyfill": "^1.7.5", diff --git a/src/components/editgrid/EditGrid.js b/src/components/editgrid/EditGrid.js index 4d850a3207..e4e304b2ea 100644 --- a/src/components/editgrid/EditGrid.js +++ b/src/components/editgrid/EditGrid.js @@ -15,7 +15,6 @@ import { const EditRowState = { New: 'new', Editing: 'editing', - Saving: 'saving', Saved: 'saved', Viewing: 'viewing', Removed: 'removed', @@ -940,11 +939,6 @@ export default class EditGridComponent extends NestedArrayComponent { editRow.components.forEach((comp) => comp.setPristine(false)); } - // Mark the row with a 'Saving' state to trigger validation for future row changes - if (editRow.state === EditRowState.New) { - editRow.state = EditRowState.Saving; - } - const errors = this.validateRow(editRow, true); if (!this.component.rowDrafts) { @@ -959,7 +953,7 @@ export default class EditGridComponent extends NestedArrayComponent { this.root.focusedComponent = null; } switch (editRow.state) { - case EditRowState.Saving: { + case EditRowState.New: { const newIndex = dataValue.length; dataValue.push(editRow.data); editRow.components.forEach(component=>component.rowIndex = newIndex); @@ -1153,7 +1147,7 @@ export default class EditGridComponent extends NestedArrayComponent { shouldValidateRow(editRow, dirty, fromSubmission) { return this.shouldValidateDraft(editRow) || - editRow.state === EditRowState.Saving || + editRow.state === EditRowState.New || editRow.state === EditRowState.Editing || editRow.alerts || fromSubmission || @@ -1169,7 +1163,7 @@ export default class EditGridComponent extends NestedArrayComponent { editGridValue[editRow.rowIndex] = editRow.data; _.set(rootValue, this.path, editGridValue); const validationProcessorProcess = (context) => this.validationProcessor(context, { dirty, silentCheck }); - editRow.errors = processSync({ + const errors = processSync({ components: fastCloneDeep(this.component.components).map((component) => { component.parentPath = `${this.path}[${editRow.rowIndex}]`; return component; @@ -1186,6 +1180,10 @@ export default class EditGridComponent extends NestedArrayComponent { } ] }).errors; + + editRow.errors = (this.component.modal || this.component.rowDrafts) + ? errors + : errors.filter((err) => _.find(this.visibleErrors, ['component.id', err.component.id])); } // TODO: this is essentially running its own custom validation and should be moved into a validation rule diff --git a/src/components/editgrid/EditGrid.unit.js b/src/components/editgrid/EditGrid.unit.js index 96d7c8bfa3..abd9c33345 100644 --- a/src/components/editgrid/EditGrid.unit.js +++ b/src/components/editgrid/EditGrid.unit.js @@ -1239,7 +1239,7 @@ describe('EditGrid Component', () => { setTimeout(() => { assert.equal(!!firstRowTextField.errors, true); assert.equal(editGrid.editRows[0].errors.length, 1); - assert.equal(editGrid.editRows[0].state, 'saving'); + assert.equal(editGrid.editRows[0].state, 'new'); document.innerHTML = ''; done(); @@ -1444,7 +1444,7 @@ describe('EditGrid Component', () => { setTimeout(() => { assert.equal(!!firstRowTextField.errors, true); assert.equal(editGrid.editRows[0].errors.length, 1); - assert.equal(editGrid.editRows[0].state, 'saving'); + assert.equal(editGrid.editRows[0].state, 'new'); document.innerHTML = ''; done(); @@ -1454,6 +1454,42 @@ describe('EditGrid Component', () => { }).catch(done); }); + it('Should trigger validation onChange before attempt to save', (done) => { + const form = _.cloneDeep(comp20); + const element = document.createElement('div'); + + Formio.createForm(element, form).then(form => { + const rootTextField = form.getComponent('text'); + rootTextField.setValue('test'); + const editGrid = form.getComponent('editGrid'); + const clickEvent = new Event('click'); + editGrid.refs['editgrid-editGrid-addRow'][0].dispatchEvent(clickEvent); + + setTimeout(() => { + const egRowTextField = editGrid.components[0]; + + const inputEvent = new Event('input'); + const textFieldEGInput = egRowTextField.refs.input[0]; + + textFieldEGInput.value = 'te'; + textFieldEGInput.dispatchEvent(inputEvent); + + setTimeout(() => { + assert.equal(editGrid.editRows[0].errors.length, 1, 'Should include custom validation error'); + assert.equal(editGrid.editRows[0].errors[0].message, 'data must match root textfield'); + textFieldEGInput.value = 'test'; + textFieldEGInput.dispatchEvent(inputEvent); + + setTimeout(() => { + assert.equal(editGrid.editRows[0].errors.length, 0, 'Should not include custom validation error'); + document.innerHTML = ''; + done(); + }, 300); + }, 300); + }, 300) + }).catch(done); + }); + it('Should not allow to save invalid row when there are required components inside columns in the editGrod row', (done) => { const formElement = document.createElement('div'); const form = new Webform(formElement); @@ -1471,7 +1507,7 @@ describe('EditGrid Component', () => { setTimeout(() => { assert.equal(editGrid.editRows.length, 1); assert.equal(editGrid.editRows[0].errors?.length, 1); - assert.equal(editGrid.editRows[0].state, 'saving'); + assert.equal(editGrid.editRows[0].state, 'new'); done(); }, 300); }, 300); diff --git a/src/components/editgrid/fixtures/comp20.js b/src/components/editgrid/fixtures/comp20.js new file mode 100644 index 0000000000..73bf07b3a5 --- /dev/null +++ b/src/components/editgrid/fixtures/comp20.js @@ -0,0 +1,42 @@ +export default { + title: "edit grid validation", + name: "EG_validation", + path: "EG_validation", + type: "form", + display: "form", + components: [ + { + label: 'Root Text', + alwaysEnabled: false, + tableView: true, + key: 'text', + type: 'textfield', + input: true + }, + { + label: "Edit Grid", + tableView: false, + validateWhenHidden: false, + rowDrafts: false, + key: "editGrid", + type: "editgrid", + displayAsTable: false, + input: true, + components: [ + { + label: 'Textfield - EG', + applyMaskOn: 'change', + tableView: true, + validate: { + custom: "valid = (input === data.text) ? true : 'data must match root textfield';" + }, + validateWhenHidden: false, + key: 'rootTest', + type: 'textfield', + alwaysEnabled: false, + input: true + }, + ], + }, + ], +}; diff --git a/src/components/editgrid/fixtures/index.js b/src/components/editgrid/fixtures/index.js index 5027789d19..a120526de8 100644 --- a/src/components/editgrid/fixtures/index.js +++ b/src/components/editgrid/fixtures/index.js @@ -17,8 +17,9 @@ import comp16 from './comp16'; import comp17 from './comp17'; import comp18 from './comp18'; import comp19 from './comp19'; +import comp20 from './comp20'; import withOpenWhenEmptyAndConditions from './comp-with-conditions-and-openWhenEmpty'; import compOpenWhenEmpty from './comp-openWhenEmpty'; import compWithCustomDefaultValue from './comp-with-custom-default-value'; import compTestEvents from './comp-test-events'; -export { comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16, comp17, comp18, comp19, compOpenWhenEmpty, withOpenWhenEmptyAndConditions, compWithCustomDefaultValue, compTestEvents }; +export { comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16, comp17, comp18, comp19, comp20, compOpenWhenEmpty, withOpenWhenEmptyAndConditions, compWithCustomDefaultValue, compTestEvents }; diff --git a/yarn.lock b/yarn.lock index d3b7e8606e..8cb8c7a0f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -275,10 +275,10 @@ fuse.js "^6.6.2" redux "^4.2.0" -"@formio/core@2.3.0-rc.16": - version "2.3.0-rc.16" - resolved "https://registry.yarnpkg.com/@formio/core/-/core-2.3.0-rc.16.tgz#1235427027e4aa19482cefca342fd3e6ed7c7744" - integrity sha512-VJRb7TG/5bK45dQ8kAoAA2Jy/ZinU4qfV6+WB3LDxL9xg0hhQoo2i+9Hrum9+pg87IGvnSvquf2/tklpTnQlfg== +"@formio/core@2.3.0-rc.17": + version "2.3.0-rc.17" + resolved "https://registry.yarnpkg.com/@formio/core/-/core-2.3.0-rc.17.tgz#63cef2248109f937b3449cc8088da12246af17e8" + integrity sha512-cpN2KXm0gfQWV38K5zkc9MiHhL3aaU8h4Aeat3bozl94CsOG/zbZ9mmQG1GRgrxrHKcb1F56VbpUyEfWOC+iWA== dependencies: "@types/json-logic-js" "^2.0.7" browser-cookies "^1.2.0"