From a55fd9b030dc9a54900f486a2a488b6749b5520c Mon Sep 17 00:00:00 2001 From: Sahar Date: Wed, 10 Sep 2025 10:31:34 +0200 Subject: [PATCH 1/2] fix: Multiselect widget selected values inside list widget --- .../MultiselectWidget_Bug 41210 _Spec.ts | 28 +++++++++++++++++++ .../MultiSelectWidgetV2/widget/index.tsx | 27 ++++++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts new file mode 100644 index 000000000000..72c6bf066bef --- /dev/null +++ b/app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts @@ -0,0 +1,28 @@ +import { locators } from "../../../../support/Objects/ObjectsCore"; +import * as _ from "../../../../support/Objects/ObjectsCore"; + +const widgetSelector = (name: string) => `[data-widgetname-cy="${name}"]`; + +describe("Bug 41210: MultiSelectWidgetV2 inside ListWidget - selected values and labels persist per item", function () { + before(() => { + _.agHelper.AddDsl("Listv2/emptyList"); + }); + + it("should persist selected values for each list item and initialize with default values on first render", function () { + cy.dragAndDropToWidget("multiselectwidgetv2", "containerwidget", { + x: 250, + y: 50, + }); + _.propPane.UpdatePropertyFieldValue("Default selected values", '["GREEN"]'); + _.agHelper.GetNClick(locators._enterPreviewMode); + _.agHelper.SelectFromMultiSelect(["Red"]); + + const listContainer = `${widgetSelector("List1")} [type="CONTAINER_WIDGET"]`; + + cy.get(listContainer).eq(1).click(); + cy.get(listContainer).eq(0).click(); + cy.get( + `${widgetSelector("MultiSelect1")} .rc-select-selection-item`, + ).should("contain.text", "Red"); + }); +}); diff --git a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx index 390121289a2e..31b58f54fad0 100644 --- a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx @@ -836,12 +836,29 @@ class MultiSelectWidget extends BaseWidget< } getWidgetView() { + const { + currentIndex, + defaultOptionValue = [], + selectedValuesByItem = {}, + updateWidgetMetaProperty, + } = this.props; + + const itemId = String(currentIndex); + let values = selectedValuesByItem[itemId] || defaultOptionValue; + + if (!selectedValuesByItem[itemId] && defaultOptionValue) { + values = defaultOptionValue as string[]; + updateWidgetMetaProperty("selectedValuesByItem", { + ...selectedValuesByItem, + [itemId]: values, + }); + } + const options = isArray(this.props.options) ? this.props.options : []; const minDropDownWidth = (MinimumPopupWidthInPercentage / 100) * (this.props.mainCanvasWidth ?? layoutConfigurations.MOBILE.maxWidth); const { componentHeight, componentWidth } = this.props; - const values = this.mergeLabelAndValue(); const isInvalid = "isValid" in this.props && !this.props.isValid && !!this.props.isDirty; @@ -887,7 +904,13 @@ class MultiSelectWidget extends BaseWidget< } onOptionChange = (value: DraftValueType) => { - this.props.updateWidgetMetaProperty("selectedOptions", value, { + const itemId = this.props.currentIndex; + const updatedValue = { + ...(this.props.selectedValuesByItem || {}), + [itemId]: value, + }; + + this.props.updateWidgetMetaProperty("selectedValuesByItem", updatedValue, { triggerPropertyName: "onOptionChange", dynamicString: this.props.onOptionChange, event: { From 633558c44379a93abcb7c220351b7887a6e63ba1 Mon Sep 17 00:00:00 2001 From: Sahar Date: Thu, 11 Sep 2025 08:29:43 +0200 Subject: [PATCH 2/2] Resolve comments --- ....ts => MultiSelectWidget_Bug41210_Spec.ts} | 0 .../MultiSelectWidgetV2/widget/index.tsx | 56 ++++++++++--------- 2 files changed, 29 insertions(+), 27 deletions(-) rename app/client/cypress/e2e/Regression/ClientSide/BugTests/{MultiselectWidget_Bug 41210 _Spec.ts => MultiSelectWidget_Bug41210_Spec.ts} (100%) diff --git a/app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts b/app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts similarity index 100% rename from app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiselectWidget_Bug 41210 _Spec.ts rename to app/client/cypress/e2e/Regression/ClientSide/BugTests/MultiSelectWidget_Bug41210_Spec.ts diff --git a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx index 31b58f54fad0..0d80f35be038 100644 --- a/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx +++ b/app/client/src/widgets/MultiSelectWidgetV2/widget/index.tsx @@ -809,6 +809,19 @@ class MultiSelectWidget extends BaseWidget< if (hasChanges && this.props.isDirty) { this.props.updateWidgetMetaProperty("isDirty", false); } + + if (hasChanges) { + const itemId = String(this.props.currentIndex); + const updatedSelectedValuesByItem = { + ...(this.props.selectedValuesByItem || {}), + [itemId]: this.props.defaultOptionValue, + }; + + this.props.updateWidgetMetaProperty( + "selectedValuesByItem", + updatedSelectedValuesByItem, + ); + } } static getSetterConfig(): SetterConfig { @@ -836,29 +849,12 @@ class MultiSelectWidget extends BaseWidget< } getWidgetView() { - const { - currentIndex, - defaultOptionValue = [], - selectedValuesByItem = {}, - updateWidgetMetaProperty, - } = this.props; - - const itemId = String(currentIndex); - let values = selectedValuesByItem[itemId] || defaultOptionValue; - - if (!selectedValuesByItem[itemId] && defaultOptionValue) { - values = defaultOptionValue as string[]; - updateWidgetMetaProperty("selectedValuesByItem", { - ...selectedValuesByItem, - [itemId]: values, - }); - } - const options = isArray(this.props.options) ? this.props.options : []; const minDropDownWidth = (MinimumPopupWidthInPercentage / 100) * (this.props.mainCanvasWidth ?? layoutConfigurations.MOBILE.maxWidth); const { componentHeight, componentWidth } = this.props; + const values = this.mergeLabelAndValue(); const isInvalid = "isValid" in this.props && !this.props.isValid && !!this.props.isDirty; @@ -925,17 +921,23 @@ class MultiSelectWidget extends BaseWidget< // { label , value } is needed in the widget mergeLabelAndValue = (): LabelInValueType[] => { - if (!this.props.selectedOptionLabels || !this.props.selectedOptionValues) { - return []; - } + const { + currentIndex, + defaultOptionValue = [], + selectedValuesByItem = {}, + updateWidgetMetaProperty, + } = this.props; + const itemId = String(currentIndex); + const values = selectedValuesByItem[itemId] || defaultOptionValue; - const labels = [...this.props.selectedOptionLabels]; - const values = [...this.props.selectedOptionValues]; + if (!selectedValuesByItem[itemId] && defaultOptionValue) { + updateWidgetMetaProperty("selectedValuesByItem", { + ...selectedValuesByItem, + [itemId]: defaultOptionValue, + }); + } - return values.map((value, index) => ({ - value, - label: labels[index], - })); + return values; }; onFilterChange = (value: string) => {