diff --git a/addons/web/static/src/core/select_menu/select_menu.js b/addons/web/static/src/core/select_menu/select_menu.js index 62402513cad..2bddf24c6bb 100644 --- a/addons/web/static/src/core/select_menu/select_menu.js +++ b/addons/web/static/src/core/select_menu/select_menu.js @@ -138,17 +138,25 @@ export class SelectMenu extends Component { }); } + async onBeforeOpen() { + if (this.state.searchValue.length) { + this.state.searchValue = ""; + if (this.props.onInput) { + // This props can be used by the parent to fetch items dynamically depending + // the search value. It must be called with the empty search value. + await this.executeOnInput(""); + } + } + this.filterOptions(); + } + onStateChanged({ open }) { this.isOpen = open; - - if (!open) { - this.state.searchValue = ""; - return; - } - - const selectedElement = document.querySelector(".o_select_active"); - if (selectedElement) { - scrollTo(selectedElement); + if (open) { + const selectedElement = document.querySelector(".o_select_active"); + if (selectedElement) { + scrollTo(selectedElement); + } } } diff --git a/addons/web/static/src/core/select_menu/select_menu.xml b/addons/web/static/src/core/select_menu/select_menu.xml index ba61fc64880..e3f4212e5d2 100644 --- a/addons/web/static/src/core/select_menu/select_menu.xml +++ b/addons/web/static/src/core/select_menu/select_menu.xml @@ -7,7 +7,7 @@ togglerClass="`o_select_menu_toggler btn w-100 bg-light ${props.togglerClass || ''} ${canDeselect ? 'o_can_deselect' : ''}`" menuClass="`o_select_menu_menu${props.searchable ? ' py-0' : ''}${props.multiSelect ? ' o_select_menu_multi_select' : ''} border`" position="'bottom-fit'" - beforeOpen.bind="filterOptions" + beforeOpen.bind="onBeforeOpen" onScroll.bind="onScroll" onStateChanged.bind="onStateChanged" > diff --git a/addons/web/static/tests/core/select_menu_tests.js b/addons/web/static/tests/core/select_menu_tests.js index 16a0ebce5ea..aeb4f45e529 100644 --- a/addons/web/static/tests/core/select_menu_tests.js +++ b/addons/web/static/tests/core/select_menu_tests.js @@ -1202,4 +1202,42 @@ QUnit.module("Web Components", (hooks) => { "options have been filtered since the choices changed" ); }); + + QUnit.test("search value is cleared when reopening the menu", async (assert) => { + class Parent extends Component { + setup() { + this.state = useState({ + choices: [ + { label: "Option A", value: "optionA" }, + ], + value: "hello", + }); + } + + onInput(searchValue) { + assert.step("search=" + searchValue); + } + } + Parent.components = { SelectMenu }; + Parent.template = xml` + + `; + + await mount(Parent, target, { env }); + await open(); + assert.verifySteps([], "onInput props has not been called initially"); + await editInput(target, "input.o_select_menu_sticky", "a"); + assert.verifySteps(["search=a"], "onInput props has been called with the right search string"); + + // opening the menu should clear the search string, trigger onInput and update the props + await triggerEvent(target, ".o_select_menu_toggler", "keydown", { key: "Escape" }); + await open(); + assert.verifySteps(["search="], "onInput props has been called with the empty search string"); + assert.strictEqual(target.querySelector(".o_select_menu_sticky").value, "", "search input is empty"); + }); });