[FIX] web: SelectMenu: fix onInput props usage

This commit fixes an issue caused by the way we use onInput props in Knowledge to
fetch articles depending the current search value. Since we start from an empty
string in the input again, it make no sense to display the choices previously
fetched with a search value no longer displayed in the UI. The only way to display
the correct items is to update the input value, then put an empty search to fetch
accordingly.

This is clearly an issue, when the onInput props is used to fetch the content of
the SelectMenu, depending of the search value. The UI obviously display an empty
search, and filter accordingly, but without fetching the items corresponding to
the empty search value.

A test was added as well to assert SelectMenu can be used for this purpose without
forgetting to call onInput again when clearing the search value in beforeOpen.

closes odoo/odoo#153072

X-original-commit: ca417f171b1bd2dd567beed7bc0e1fcaba6c8a4c
Signed-off-by: Bastien Fafchamps (bafa) <bafa@odoo.com>
Signed-off-by: Luca Vitali (luvi) <luvi@odoo.com>
This commit is contained in:
luvi
2024-02-07 18:34:22 +00:00
parent 1365dad144
commit f8a53d3a11
3 changed files with 56 additions and 10 deletions
@@ -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);
}
}
}
@@ -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"
>
@@ -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`
<SelectMenu
choices="state.choices"
groups="state.groups"
value="state.value"
onInput.bind="onInput"
/>
`;
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");
});
});