[FIX] web: fix filtering when choices/groups props update

This commit fixes the filtering of choices when the choices or the groups
props values are updated. Before this commit, the filter was only triggered
when the length of choices or groups differ.

Instead, it is prefered to apply the filter of choices whenever those props
are updated (in a dedicated useEffect).

A test has been added, updating the choices props, while having an object with
the same number of choices, while having different values. Before this fix, the
filtering wouldn't be applied correctly, since the filter wouldn't be triggered
because the object has the same number of values in it.

closes odoo/odoo#127733

Signed-off-by: Bastien Fafchamps (bafa) <bafa@odoo.com>
This commit is contained in:
luvi
2023-07-07 16:42:38 +02:00
parent dce30f6b72
commit 8a4485748f
2 changed files with 69 additions and 8 deletions
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { Component, useState, useRef, onWillUpdateProps } from "@odoo/owl";
import { Component, useState, useRef, onWillUpdateProps, useEffect } from "@odoo/owl";
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { _lt } from "@web/core/l10n/translation";
@@ -94,14 +94,14 @@ export class SelectMenu extends Component {
if (this.props.value !== nextProps.value) {
this.selectedChoice = this.getSelectedChoice(nextProps);
}
if (
this.props.choices.length !== nextProps.choices.length ||
this.props.groups.length !== nextProps.groups.length
) {
const groups = [{ choices: nextProps.choices }, ...nextProps.groups];
this.filterOptions(this.state.searchValue, groups);
}
});
useEffect(
() => {
const groups = [{ choices: this.props.choices }, ...this.props.groups];
this.filterOptions(this.state.searchValue, groups);
},
() => [this.props.choices, this.props.groups]
);
}
get displayValue() {
@@ -912,6 +912,7 @@ QUnit.module("Web Components", (hooks) => {
);
await editInput(target, "input.o_select_menu_sticky", "cou");
await nextTick();
assert.strictEqual(
target.querySelector(".o_select_menu_menu").textContent,
"Coucou",
@@ -929,4 +930,64 @@ QUnit.module("Web Components", (hooks) => {
"SelectMenu has two choices available"
);
});
QUnit.test("Choices are updated and filtered when props change", async (assert) => {
class Parent extends Component {
setup() {
this.state = useState({
choices: [
{ label: "Hello", value: "hello" },
{ label: "Coucou", value: "hello2" },
],
value: "hello",
});
}
onInput() {
this.state.choices = [
{ label: "Coucou", value: "hello2" },
{ label: "Good afternoon", value: "hello3" },
];
}
onSelect(value) {
assert.step(value);
this.state.value = value;
}
}
Parent.components = { SelectMenu };
Parent.template = xml`
<SelectMenu
choices="state.choices"
value="state.value"
onInput.bind="onInput"
onSelect.bind="onSelect"
/>
`;
await mount(Parent, target, { env });
assert.strictEqual(getValue(), "Hello");
await open();
assert.strictEqual(
target.querySelector(".o_select_menu_menu").textContent,
"CoucouHello",
"SelectMenu has two choices available"
);
// edit the input, to trigger onInput and update the props
await editInput(target, "input.o_select_menu_sticky", "aft");
await nextTick();
await click(target.querySelectorAll(".o_select_menu_item_label")[0]);
assert.verifySteps(["hello3"], "added item can be selected");
assert.strictEqual(getValue(), "Good afternoon");
await open();
assert.strictEqual(
target.querySelector(".o_select_menu_menu").textContent,
"CoucouGood afternoon",
"SelectMenu has two updated choices available"
);
});
});