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 7eb9d3824e3..a32a9ec0294 100644 --- a/addons/web/static/src/views/fields/input_field_hook.js +++ b/addons/web/static/src/views/fields/input_field_hook.js @@ -33,6 +33,14 @@ export function useInputField(params) { */ let lastSetValue = null; + /** + * Track the fact that there is a change sent to the model that hasn't been acknowledged yet + * (e.g. because the onchange is still pending). This is necessary if we must do an urgent save, + * as we have to re-send that change for the write that will be done directly. + * FIXME: this could/should be handled by the model itself, when it will be rewritten + */ + let pendingUpdate = false; + /** * When a user types, we need to set the field as dirty. */ @@ -64,7 +72,10 @@ export function useInputField(params) { } if (!isInvalid) { - component.props.update(val); + pendingUpdate = true; + Promise.resolve(component.props.update(val)).then(() => { + pendingUpdate = false; + }); lastSetValue = ev.target.value; } @@ -126,7 +137,7 @@ export function useInputField(params) { } isDirty = inputRef.el.value !== lastSetValue; - if (isDirty || urgent) { + if (isDirty || (urgent && pendingUpdate)) { let isInvalid = false; isDirty = false; let val = inputRef.el.value; diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index 0414cbe1ac1..a04cbee6fc8 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -11868,6 +11868,35 @@ QUnit.module("Views", (hooks) => { assert.verifySteps([], "should not save because we do not change anything"); }); + QUnit.test( + "Auto save: save on closing tab/browser (not dirty but trailing spaces)", + async function (assert) { + serverData.models.partner.fields.foo.trim = true; + serverData.models.partner.records[0].foo = "name with trailing spaces "; + + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: `
`, + resId: 1, + mockRPC(route, { args, method, model }) { + if (method === "write" && model === "partner") { + throw new Error("no write should be done"); + } + }, + }); + + assert.strictEqual( + target.querySelector(".o_field_widget[name=foo] input").value, + "name with trailing spaces " + ); + + window.dispatchEvent(new Event("beforeunload")); + await nextTick(); + } + ); + QUnit.test( "Auto save: save on closing tab/browser (not dirty) with text field", async function (assert) {