diff --git a/packages/main/cypress/specs/ToolbarSelect.cy.tsx b/packages/main/cypress/specs/ToolbarSelect.cy.tsx
index 3da2eb1a5b6a..912973538ce2 100644
--- a/packages/main/cypress/specs/ToolbarSelect.cy.tsx
+++ b/packages/main/cypress/specs/ToolbarSelect.cy.tsx
@@ -1,6 +1,7 @@
import Toolbar from "../../src/Toolbar.js";
import ToolbarSelect from "../../src/ToolbarSelect.js";
import ToolbarSelectOption from "../../src/ToolbarSelectOption.js";
+import Button from "../../src/Button.js";
describe("Toolbar general interaction", () => {
it("Should render the select with the correct attributes", () => {
@@ -264,10 +265,10 @@ describe("Toolbar general interaction", () => {
cy.mount(
- 1
- 2
- 3
-
+ 1
+ 2
+ 3
+
);
cy.viewport(220, 1080); // Set a small viewport width to trigger overflow
@@ -282,4 +283,47 @@ describe("Toolbar general interaction", () => {
// Verify the toolbar-select is rendered inside the popover
cy.get("ui5-toolbar-select").should("be.visible");
});
+
+ it("Should update ToolbarSelect value when option selected property changes via button click", () => {
+ cy.mount(
+ <>
+
+
+ Option 1
+ Option 2
+
+
+
+ >
+ );
+
+ // Wait for component to render
+ cy.wait(500);
+
+ // Initial check - Option 1 should be selected
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .should("have.prop", "value", "Option 1");
+
+ // Set up button click handler
+ cy.get("[ui5-button]").then($btn => {
+ $btn.get(0).addEventListener("click", () => {
+ const opt1 = document.getElementById("opt1") as ToolbarSelectOption;
+ const opt2 = document.getElementById("opt2") as ToolbarSelectOption;
+ opt1.selected = false;
+ opt2.selected = true;
+ });
+ });
+
+ // Click the button
+ cy.get("[ui5-button]").realClick();
+
+ // Wait for update
+ cy.wait(200);
+
+ // Verify the ToolbarSelect value property updated
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .should("have.prop", "value", "Option 2");
+ });
});
\ No newline at end of file
diff --git a/packages/main/src/ToolbarSelect.ts b/packages/main/src/ToolbarSelect.ts
index 2e8451f9973d..cb5ccdbe1b0b 100644
--- a/packages/main/src/ToolbarSelect.ts
+++ b/packages/main/src/ToolbarSelect.ts
@@ -4,6 +4,7 @@ import property from "@ui5/webcomponents-base/dist/decorators/property.js";
import slot from "@ui5/webcomponents-base/dist/decorators/slot.js";
import event from "@ui5/webcomponents-base/dist/decorators/event-strict.js";
import type ValueState from "@ui5/webcomponents-base/dist/types/ValueState.js";
+import type { ChangeInfo } from "@ui5/webcomponents-base/dist/UI5Element.js";
import ToolbarSelectCss from "./generated/themes/ToolbarSelect.css.js";
import type Select from "./Select.js";
@@ -91,6 +92,7 @@ class ToolbarSelect extends ToolbarItem {
@slot({
"default": true,
type: HTMLElement,
+ invalidateOnChildChange: true,
})
options!: Array;
@@ -146,14 +148,19 @@ class ToolbarSelect extends ToolbarItem {
*/
@property()
set value(newValue: string) {
- if (this.select && this.select.value !== newValue) {
- this.select.value = newValue;
- }
this._value = newValue;
+ const selectElement = this.select;
+ if (selectElement && selectElement.value !== newValue) {
+ selectElement.value = newValue;
+ }
}
get value(): string | undefined {
- return this.select ? this.select.value : this._value;
+ // Always return _value if it's set, as it represents the source of truth
+ if (this._value !== undefined && this._value !== "") {
+ return this._value;
+ }
+ return this.select ? this.select.value : undefined;
}
get select(): Select | null {
@@ -163,6 +170,30 @@ class ToolbarSelect extends ToolbarItem {
// Internal value storage, in case the composite select is not rendered on the the assignment happens
_value: string = "";
+ onInvalidation(changeInfo: ChangeInfo) {
+ // When a child ToolbarSelectOption's selected property changes, update the value
+ if (changeInfo.reason === "childchange") {
+ const selectedOption = this.options.find(option => option.selected);
+ if (selectedOption) {
+ const newValue = selectedOption.textContent || "";
+ // Update both internal value and the select component's value
+ this._value = newValue;
+ // Cache the select reference to avoid multiple DOM queries
+ const selectElement = this.select;
+ if (selectElement && selectElement.value !== newValue) {
+ selectElement.value = newValue;
+ }
+ } else {
+ // If no option is selected, clear the value
+ this._value = "";
+ const selectElement = this.select;
+ if (selectElement) {
+ selectElement.value = "";
+ }
+ }
+ }
+ }
+
onClick(e: Event): void {
e.stopImmediatePropagation();
const prevented = !this.fireDecoratorEvent("click", { targetRef: e.target as HTMLElement });
@@ -189,12 +220,16 @@ class ToolbarSelect extends ToolbarItem {
onChange(e: CustomEvent): void {
e.stopImmediatePropagation();
+
+ // Update internal value BEFORE firing the change event
+ // so that when event listeners read this.value, they get the updated value
+ this._value = e.detail.selectedOption?.textContent || "";
+ this._syncOptions(e.detail.selectedOption);
+
const prevented = !this.fireDecoratorEvent("change", { ...e.detail, targetRef: e.target as HTMLElement });
if (!prevented) {
this.fireDecoratorEvent("close-overflow");
}
-
- this._syncOptions(e.detail.selectedOption);
}
_syncOptions(selectedOption: HTMLElement): void {