diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index b2c061f49e7..b4d343d7eb0 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -1049,6 +1049,13 @@ var BasicModel = AbstractModel.extend({ args: [idList, currentData, fields, onchange_spec, context], }) .then(function (result) { + if (!record._changes) { + // if the _changes key does not exist anymore, it means that + // it was removed by discarding the changes after the rpc + // to onchange. So, in that case, the proper response is to + // ignore the onchange. + return; + } if (result.warning) { self.trigger_up('warning', { message: result.warning.message, diff --git a/addons/web/static/test/views/form_tests.js b/addons/web/static/test/views/form_tests.js index 651819a7c37..66d9d64090c 100644 --- a/addons/web/static/test/views/form_tests.js +++ b/addons/web/static/test/views/form_tests.js @@ -2058,5 +2058,57 @@ QUnit.module('Views', { }); } }); + + QUnit.test('onchanges that complete after discarding', function (assert) { + assert.expect(4); + + var def1 = $.Deferred(); + + this.data.partner.onchanges = { + foo: function (obj) { + obj.int_field = obj.foo.length + 1000; + }, + }; + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
', + res_id: 2, + mockRPC: function (route, args) { + var result = this._super.apply(this, arguments); + if (args.method === 'onchange') { + assert.step('onchange is done'); + return def1.then(function () { + return result; + }); + } + return result; + }, + }); + + // go into edit mode + assert.strictEqual(form.$('span[name="foo"]').text(), "blip", + "field foo should be displayed to initial value"); + form.$buttons.find('.o_form_button_edit').click(); + + // edit a value + form.$('input').first().val("1234").trigger('input'); + + // discard changes + form.$buttons.find('.o_form_button_cancel').click(); + $('.modal .modal-footer .btn-primary').click(); + assert.strictEqual(form.$('span[name="foo"]').text(), "blip", + "field foo should still be displayed to initial value"); + + // complete the onchange + def1.resolve(); + assert.strictEqual(form.$('span[name="foo"]').text(), "blip", + "field foo should still be displayed to initial value"); + + form.destroy(); + }); }); });