From 6ba7254b1292b15fb4328b744f0b75a89deaaff9 Mon Sep 17 00:00:00 2001 From: sanja <52755494+sanjacornelius@users.noreply.github.com> Date: Thu, 30 Jul 2026 12:22:20 -0700 Subject: [PATCH] Isolate FormRecordList modal validations Prevent record-list modal fields from affecting parent screen validation. Add NoOpValidations and return it for FormRecordList in ValidationsFactory so modal fields are not included in parent validation rules. Add an "isolated" prop to vue-form-renderer to stop modal renderers from propagating validation updates to the parent, and set isolated=true for add/edit renderers in form-record-list. --- src/ValidationsFactory.js | 14 ++++++++-- src/components/renderer/form-record-list.vue | 29 ++++++++++++++++++-- src/components/vue-form-renderer.vue | 8 +++++- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/ValidationsFactory.js b/src/ValidationsFactory.js index 23e0210ea..5c67eacd7 100644 --- a/src/ValidationsFactory.js +++ b/src/ValidationsFactory.js @@ -235,6 +235,15 @@ class PageNavigateValidations extends Validations { } } +/** + * No-op validations (e.g. FormRecordList — modal fields validate separately) + */ +class NoOpValidations extends Validations { + async addValidations() { + // intentionally empty + } +} + /** * Add validations for a form element */ @@ -400,8 +409,9 @@ function ValidationsFactory(element, options) { return new FormLoopValidations(element, options); } if (element.component === 'FormRecordList') { - //not required - //return new FormRecordListValidations(element, screen); + // Record list modal fields are validated only when submitting the modal, + // not as part of the parent screen's validation rules. + return new NoOpValidations(element, options); } if (element.component === 'FormButton' && element.config.event === 'pageNavigate') { return new PageNavigateValidations(element, options); diff --git a/src/components/renderer/form-record-list.vue b/src/components/renderer/form-record-list.vue index e76faaa3c..b6de26ec8 100644 --- a/src/components/renderer/form-record-list.vue +++ b/src/components/renderer/form-record-list.vue @@ -182,6 +182,7 @@ :current-page="form" :computed="formComputed" :watchers="formWatchers" + :isolated="true" debug-context="Record List Add" :_parent="validationData" @update="updateRowDataNamePrefix" @@ -198,7 +199,7 @@ header-close-content="×" data-cy="modal-edit" @ok="edit" - @hidden="$refs.addRenderer.hasSubmitted(false)" + @hidden="handleHideEditModal" @shown="emitShownEvent" > import _ from "lodash"; +import { mapActions } from "vuex"; import { dateUtils } from "@processmaker/vue-form-elements"; import VueFormRenderer from "@/components/vue-form-renderer.vue"; import mustacheEvaluation from "../../mixins/mustacheEvaluation"; import MustacheHelper from "../inspector/mustache-helper.vue"; import Mustache from "mustache"; +import { findRootScreen } from "@/mixins/DataReference"; const jsonOptionsActionsColumn = { key: "__actions", @@ -507,6 +511,7 @@ export default { this.$root.$emit("record-list-option", this.source?.sourceOptions); }, methods: { + ...mapActions("globalErrorsModule", ["validateNow", "close"]), togglePopover(index, event, rowId) { this.deleteIndex = _.find(this.tableData.data, { row_id: rowId }); this.isPopoverVisible = this.isPopoverVisible === index ? null : index; @@ -991,7 +996,7 @@ export default { }); }, edit(event) { - this.$refs.addRenderer.hasSubmitted(true); + this.$refs.editRenderer.hasSubmitted(true); if ( this.$refs.editRenderer.$refs.renderer.$refs.component.$v.vdata.$invalid ) { @@ -1030,7 +1035,25 @@ export default { }, handleHideAddModal() { this.addItem = this.initFormValues; - this.$refs.addRenderer.hasSubmitted(false); + if (this.$refs.addRenderer) { + this.$refs.addRenderer.hasSubmitted(false); + } + this.restoreParentValidationState(); + }, + handleHideEditModal() { + if (this.$refs.editRenderer) { + this.$refs.editRenderer.hasSubmitted(false); + } + this.restoreParentValidationState(); + }, + restoreParentValidationState() { + // Clear modal-driven global submit flags and refresh parent validity + // so required modal fields (e.g. FormCheckbox) never block parent submit. + this.close(); + const rootScreen = findRootScreen(this); + if (rootScreen && typeof rootScreen.loadValidationRules === "function") { + this.validateNow(rootScreen); + } }, async handleOk(bvModalEvt) { this.$refs.addRenderer.hasSubmitted(true); diff --git a/src/components/vue-form-renderer.vue b/src/components/vue-form-renderer.vue index 26fc57ccf..35957a356 100644 --- a/src/components/vue-form-renderer.vue +++ b/src/components/vue-form-renderer.vue @@ -64,7 +64,10 @@ export default { "showErrors", "testScreenDefinition", "deviceScreen", - "taskdraft" + "taskdraft", + // When true, local $v is still used (e.g. record list modals) but data + // changes do not update the parent form's global valid/submit state. + "isolated" ], data() { return { @@ -152,6 +155,9 @@ export default { deep: true, handler() { this.$emit("update", this.data); + if (this.isolated) { + return; + } const mainScreen = this.getMainScreen(); if (mainScreen) { this.validate(mainScreen);