diff --git a/addons/web/static/src/js/control_panel/custom_filter_item.js b/addons/web/static/src/js/control_panel/custom_filter_item.js
index 29fc35084a5..a996cfe97cf 100644
--- a/addons/web/static/src/js/control_panel/custom_filter_item.js
+++ b/addons/web/static/src/js/control_panel/custom_filter_item.js
@@ -107,6 +107,7 @@ odoo.define('web.CustomFilterItem', function (require) {
const fieldType = this.fields[condition.field].type;
const genericType = FIELD_TYPES[fieldType];
const operator = FIELD_OPERATORS[genericType][condition.operator];
+ // Logical value
switch (genericType) {
case 'id':
case 'number':
@@ -131,6 +132,12 @@ odoo.define('web.CustomFilterItem', function (require) {
default:
condition.value = "";
}
+ // Displayed value
+ if (["float", "monetary"].includes(fieldType)) {
+ condition.displayedValue = `0${this.DECIMAL_POINT}0`;
+ } else {
+ condition.displayedValue = String(condition.value);
+ }
}
//---------------------------------------------------------------------
@@ -237,20 +244,25 @@ odoo.define('web.CustomFilterItem', function (require) {
* @param {Event} ev
*/
_onValueInput(condition, ev) {
- const type = this.fields[condition.field].type;
- if (['float', 'integer', 'id'].includes(type)) {
- const previousValue = condition.value;
- const parser = field_utils.parse[type === 'float' ? 'float' : 'integer'];
+ if (!ev.target.value) {
+ return this._setDefaultValue(condition);
+ }
+ let { type } = this.fields[condition.field];
+ if (type === "id") {
+ type = "integer";
+ }
+ if (FIELD_TYPES[type] === "number") {
try {
- const parsed = parser(ev.target.value || 0);
- // Force parsed value in the input.
- ev.target.value = condition.value = (parsed || 0);
+ // Write logical value into the 'value' property
+ condition.value = field_utils.parse[type](ev.target.value);
+ // Write displayed value in the input and 'displayedValue' property
+ condition.displayedValue = ev.target.value;
} catch (err) {
- // Force previous value if non-parseable.
- ev.target.value = previousValue || 0;
+ // Parsing error: reverts to previous value
+ ev.target.value = condition.displayedValue;
}
} else {
- condition.value = ev.target.value || "";
+ condition.value = condition.displayedValue = ev.target.value;
}
}
}
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 8dcde9c934e..c3655c8d47c 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -390,20 +390,20 @@
t-att-type="DECIMAL_POINT === '.' ? 'number' : 'text'"
t-attf-title="Number using {{ DECIMAL_POINT }} as decimal separator."
t-attf-pattern="[0-9]+([\\{{ DECIMAL_POINT }}][0-9]+)?"
- t-att-value="condition.value or (0 + DECIMAL_POINT + 0)"
+ t-att-value="condition.displayedValue"
t-on-input="_onValueInput(condition)"
/>
diff --git a/addons/web/static/tests/control_panel/custom_filter_item_tests.js b/addons/web/static/tests/control_panel/custom_filter_item_tests.js
index e00610bba44..89e64d2d613 100644
--- a/addons/web/static/tests/control_panel/custom_filter_item_tests.js
+++ b/addons/web/static/tests/control_panel/custom_filter_item_tests.js
@@ -327,7 +327,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
});
QUnit.test('input value parsing', async function (assert) {
- assert.expect(6);
+ assert.expect(7);
const cfi = await createComponent(CustomFilterItem, {
props: {
@@ -352,16 +352,63 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
assert.strictEqual(idInput.value, "0");
// Float parsing
- await testUtils.fields.editInput(floatInput, 4.2);
+ await testUtils.fields.editInput(floatInput, "4.2");
assert.strictEqual(floatInput.value, "4.2");
await testUtils.fields.editInput(floatInput, "DefinitelyValidFloat");
- assert.strictEqual(floatInput.value, "4.2");
+ // String input in a number input gives "", which is parsed as 0
+ assert.strictEqual(floatInput.value, "0.0");
// Number parsing
- await testUtils.fields.editInput(idInput, 4);
+ await testUtils.fields.editInput(idInput, "4");
+ assert.strictEqual(idInput.value, "4");
+ await testUtils.fields.editInput(idInput, "4.2");
assert.strictEqual(idInput.value, "4");
await testUtils.fields.editInput(idInput, "DefinitelyValidID");
- assert.strictEqual(idInput.value, "4");
+ // String input in a number input gives "", which is parsed as 0
+ assert.strictEqual(idInput.value, "0");
+
+ cfi.destroy();
+ });
+
+ QUnit.test('input value parsing with language', async function (assert) {
+ assert.expect(5);
+
+ const cfi = await createComponent(CustomFilterItem, {
+ props: {
+ fields: this.fields,
+ },
+ env: {
+ searchModel: new ActionModel(),
+ _t: Object.assign(s => s, { database: { parameters: { decimal_point: "," } }}),
+ },
+ translateParameters: {
+ decimal_point: ",",
+ thousands_sep: "",
+ grouping: [3, 0],
+ },
+ });
+
+ await cpHelpers.toggleAddCustomFilter(cfi);
+ await testUtils.dom.click('button.o_add_condition');
+
+ const [floatSelect] = cfi.el.querySelectorAll('.o_generator_menu_field');
+ await testUtils.fields.editSelect(floatSelect, 'float_field');
+
+ const [floatInput] = cfi.el.querySelectorAll('.o_generator_menu_value .o_input');
+
+ // Default values
+ assert.strictEqual(floatInput.value, "0,0");
+
+ // Float parsing
+ await testUtils.fields.editInput(floatInput, '4,');
+ assert.strictEqual(floatInput.value, "4,");
+ await testUtils.fields.editInput(floatInput, '4,2');
+ assert.strictEqual(floatInput.value, "4,2");
+ await testUtils.fields.editInput(floatInput, '4,2,');
+ assert.strictEqual(floatInput.value, "4,2");
+ await testUtils.fields.editInput(floatInput, "DefinitelyValidFloat");
+ // The input here is a string, resulting in a parsing error instead of 0
+ assert.strictEqual(floatInput.value, "4,2");
cfi.destroy();
});