diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index 71b2a14c434..fdefb2cf967 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -114,7 +114,7 @@ var DebouncedField = AbstractField.extend({ */ commitChanges: function () { if (this._isDirty && this.mode === 'edit') { - this._doAction(); + return this._doAction(); } }, @@ -135,7 +135,7 @@ var DebouncedField = AbstractField.extend({ // do anything (commitChanges ensures that if it has local changes, they // are triggered up before the widget is destroyed, if necessary). if (!this.isDestroyed()) { - this._setValue(this._getValue()); + return this._setValue(this._getValue()); } }, /** diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js index f3125c72f29..7683cd6db94 100644 --- a/addons/web/static/src/js/fields/relational_fields.js +++ b/addons/web/static/src/js/fields/relational_fields.js @@ -1124,6 +1124,14 @@ var FieldX2Many = AbstractField.extend({ operation: 'UPDATE', id: ev.data.dataPointID, data: changes, + }).done(function () { + if (ev.data.onSuccess) { + ev.data.onSuccess(); + } + }).fail(function () { + if (ev.data.onFailure) { + ev.data.onFailure(); + } }); } }, diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index 5c33a32b6d5..37bd7b153c7 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -487,22 +487,24 @@ ListRenderer.include({ * @private */ _moveToNextLine: function () { + var self = this; var record = this.state.data[this.currentRow]; - var fieldNames = this.canBeSaved(record.id); - if (fieldNames.length) { - return; - } + this.commitChanges(record.id).then(function () { + var fieldNames = self.canBeSaved(record.id); + if (fieldNames.length) { + return; + } - if (this.currentRow < this.state.data.length - 1) { - this._selectCell(this.currentRow + 1, 0); - } else { - var self = this; - this.unselectRow().then(function () { - self.trigger_up('add_record', { - onFail: self._selectCell.bind(self, 0, 0, {}), + if (self.currentRow < self.state.data.length - 1) { + self._selectCell(self.currentRow + 1, 0); + } else { + self.unselectRow().then(function () { + self.trigger_up('add_record', { + onFail: self._selectCell.bind(self, 0, 0, {}), + }); }); - }); - } + } + }); }, /** * @override diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index 245ff8f7a07..77b2c403b8c 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -10168,6 +10168,72 @@ QUnit.module('relational_fields', { form.destroy(); }); + QUnit.test('one2many with onchange, required field, shortcut enter', function (assert) { + assert.expect(5); + + this.data.turtle.onchanges = { + turtle_foo: function () {}, + }; + + var def; + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
', + mockRPC: function (route, args) { + var result = this._super.apply(this, arguments); + if (args.method === 'onchange') { + return $.when(def).then(_.constant(result)); + } + return result; + }, + // simulate what happens in the client: + // the new value isn't notified directly to the model + fieldDebounce: 5000, + }); + + var value = "hello"; + + // add a new line + form.$('.o_field_x2many_list_row_add a').click(); + + // we want to add a delay to simulate an onchange + def = $.Deferred(); + + // write something in the field + var $input = form.$('input[name="turtle_foo"]'); + $input.val(value).trigger('input'); + + // trigger keydown ENTER + $input.trigger($.Event('keydown', { + keyCode: $.ui.keyCode.ENTER, + which: $.ui.keyCode.ENTER, + })); + + // check that nothing changed before the onchange finished + assert.strictEqual($input.val(), value, "input content shouldn't change"); + assert.strictEqual(form.$('.o_data_row').length, 1, + "should still contain only one row"); + + // unlock onchange + def.resolve(); + + // check the current line is added with the correct content and a new line is editable + assert.strictEqual(form.$('td.o_data_cell').text(), value); + assert.strictEqual(form.$('input[name="turtle_foo"]').val(), ''); + assert.strictEqual(form.$('.o_data_row').length, 2, + "should now contain two rows"); + + form.destroy(); + }); + QUnit.module('FieldMany2Many'); QUnit.test('many2many kanban: edition', function (assert) {