Repository navigation
fix(ui5-toolbar-select): display not updating on programmatic option selection - #13751
Conversation
|
🚀 Deployed on https://pr-13751--ui5-webcomponents-preview.netlify.app |
PetyaMarkovaBogdanova
left a comment
There was a problem hiding this comment.
Findings
High: explicit clearing via value = "" no longer updates the inner select once rendered
ToolbarSelect.ts:152 returns early for falsy values and never forwards empty string to the rendered inner Select.
Impact: after the component is mounted, setting value to empty string can leave the old visual selection in place, which is a behavioral regression for programmatic API use.
High: stale _value can override later programmatic selected changes
In ToolbarSelect.ts:164, getter prioritizes _value when present.
In ToolbarSelect.ts:220, _value is cleared only when select.value !== _value.
If initial value matches current select.value on first render, _value stays set. A later selected change on options can then be overwritten in ToolbarSelect.ts:221, forcing old _value back into the inner Select. This can reintroduce a display/source mismatch in mixed usage flows.
Medium: regression tests do not cover the two risky value lifecycle paths above
The added test in ToolbarSelect.cy.tsx:348 validates multi-selected normalization and inner option sync, but there is no coverage for:
setting value to empty string after render
initializing with value, then changing selected programmatically later (stale _value path)
Open Questions / Assumptions
Should value = "" be treated as a real API command to clear selection post-render, or only as init-time absence?
Is _value intended to be strictly pre-render staging only? If yes, it should be cleared deterministically after first render pass, not conditionally.
Change Summary
The core direction is good and addresses the reported root causes: removing custom selected accessors in ToolbarSelectOption and dropping value forwarding in the template are both correct. The remaining risk is concentrated in ToolbarSelect value staging/clearing logic, which currently introduces two high-probability edge regressions.
…mmatic-selection-sync
|
Standards
Code smells (judgement calls)
Scope creep — not in spec onBeforeRendering writes to child selected can schedule a re-render loop — ToolbarSelect.ts:211 Summary: Standards — 4 hard violations, 3 smells; worst is imperative DOM mutation replacing the template binding the fix was meant to restore. Spec — 2 high gaps (empty-string staging and getter _value priority), 2 scope-creep additions, 1 internal contradiction between the new option.value property and the getter's textContent fallback. |
|
Hey @PetyaMarkovaBogdanova, thanks for flagging this! About point 4 from the last review, the reason
The precedent for this pattern is |
|
🧹 Preview deployment cleaned up: https://pr-13751--ui5-webcomponents.netlify.app |
|
🎉 This PR is included in version v2.26.0-rc.1 🎉 The release is available on v2.26.0-rc.1 Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version v2.26.0 🎉 The release is available on v2.26.0 Your semantic-release bot 📦🚀 |
Problem
Since v2.15.0, changing the selected option programmatically (setting
ToolbarSelectOption.selected = true/false) correctly updated the outerui5-toolbar-select-optionelements but left the innerui5-selectdisplay frozen on the initially selected option.Two root causes
ToolbarSelectOptionhad a custom getter readinghasAttribute("selected"). The framework sets the DOM attribute before calling the property setter, so change detection always sawold === newand skipped invalidation — meaningToolbarSelectnever re-rendered on programmatic changes.The template passed
value={this.value}to the inner<Select>, feeding_valueStorageon every render. Once set,Select._applySelectionByValuelocks the display to the stored string and ignores theselectedattribute on inner options entirely.Solution
ToolbarSelectOption— reverted to plain@property, removing the broken getter/setter. Framework change detection now works correctly.ToolbarSelectTemplate— replacedvalue={this.value}withvalue={this._innerSelectValue}, driving the innerSelectvia its non-deprecatedvalueAPI rather than the deprecatedoption.selectedpath.ToolbarSelect:valuesetter: if options are already available, resolves immediately by settingselectedon the matching outer option (empty string clears all). If options are not yet available (pre-render), stages the value in_pendingValue/_hasPendingValue.valuegetter: reads from_lastSelectedIndex, the single computed source of truth, so getter and visual display always agree.onBeforeRendering: drains_pendingValueonce options become available. Computes_lastSelectedIndex(last selected wins, mirroringSelect._applyAutoSelection)._innerSelectValuegetter: returns the selected option's value/text for the innerSelect'svalue=binding. Returns a sentinel string when nothing is selected, routing through_applySelectionByValueinstead of_applyAutoSelection— preventing the inner select from forcing index 0 on clear._syncOptions: clears pending value on user interaction so a priorvalue=assignment cannot override the user's choice.Fixes: #12619