diff --git a/addons/web/static/src/views/fields/input_field_hook.js b/addons/web/static/src/views/fields/input_field_hook.js index 8f39485ac17..e77a75cf77a 100644 --- a/addons/web/static/src/views/fields/input_field_hook.js +++ b/addons/web/static/src/views/fields/input_field_hook.js @@ -110,12 +110,16 @@ export function useInputField(params) { * If it is not such a case, we update the field with the new value. */ useEffect(() => { + // We need to call getValue before the condition to always observe + // the corresponding value in the record. Otherwise, in some cases, + // if the value in the record change the useEffect isn't triggered. + const value = params.getValue(); if ( inputRef.el && !isDirty && !component.props.record.isFieldInvalid(component.props.name) ) { - inputRef.el.value = params.getValue(); + inputRef.el.value = value; lastSetValue = inputRef.el.value; } }); diff --git a/addons/web/static/tests/views/fields/char_field_tests.js b/addons/web/static/tests/views/fields/char_field_tests.js index cd0346cccc6..ca74fc69d19 100644 --- a/addons/web/static/tests/views/fields/char_field_tests.js +++ b/addons/web/static/tests/views/fields/char_field_tests.js @@ -721,6 +721,77 @@ QUnit.module("Fields", (hooks) => { } ); + QUnit.test( + "input field: change value before pending onchange returns (2)", + async function (assert) { + serverData.models.partner.onchanges = { + int_field(obj) { + if (obj.int_field === 7) { + obj.foo = "blabla"; + } else { + obj.foo = "tralala"; + } + }, + }; + + const def = makeDeferred(); + await makeView({ + type: "form", + resModel: "partner", + resId: 1, + serverData, + arch: ` +
+ + + + +
`, + async mockRPC(route, { method }) { + if (method === "onchange") { + await def; + } + }, + }); + assert.strictEqual( + target.querySelector(".o_field_widget[name='foo'] input").value, + "yop", + "should contain the correct value" + ); + + // trigger a deferred onchange + await editInput(target, ".o_field_widget[name='int_field'] input", "7"); + + // insert a value in input foo + target.querySelector(".o_field_widget[name=foo] input").value = "test"; + await triggerEvent(target, ".o_field_widget[name=foo] input", "input"); + + // complete the onchange + def.resolve(); + await nextTick(); + assert.strictEqual( + target.querySelector(".o_field_widget[name='foo'] input").value, + "test", + "The onchange value should not be applied because the input is in edition" + ); + + // apply the value of the input foo + await triggerEvent(target, ".o_field_widget[name=foo] input", "change"); + assert.strictEqual( + target.querySelector(".o_field_widget[name='foo'] input").value, + "test" + ); + + // trigger another onchange (not deferred) + await editInput(target, ".o_field_widget[name='int_field'] input", "10"); + assert.strictEqual( + target.querySelector(".o_field_widget[name='foo'] input").value, + "tralala", + "the onchange value should be applied because the input is not in edition" + ); + } + ); + QUnit.test( "input field: change value before pending onchange returns (with fieldDebounce)", async function (assert) {