[FIX] web: allow o2m navigation to work from required inputs

In a one2many, pressing ENTER or TAB from a required input (of type text or char) that is on the last editable column of its line would fail to navigate to next line.

The issue was that the validation of the required field would happen before the change to its value was actually applied.

This commit fixes it.

PR: #26430
Task: 1869469
This commit is contained in:
Sébastien Theys
2018-08-22 11:51:30 +02:00
parent 46bfe9ad65
commit 241704536d
4 changed files with 91 additions and 15 deletions
@@ -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());
}
},
/**
@@ -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();
}
});
}
},
@@ -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
@@ -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: '<form string="Partners">' +
'<field name="turtles">' +
'<tree editable="bottom">' +
'<field name="turtle_foo" required="1"/>' +
'</tree>' +
'</field>' +
'</form>',
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) {