[FIX] web: save a record before the onchange is complete in o2m
Before this commit, the save button in the x2m form view dialog does
not wait for ongoing updates.
Why is this?
When you click on the "Save and Close" button of a form view dialog
in an x2m, you check the validity of the record to know whether you
should save or not. The askChanges function called does not wait for
ongoing updates.
Solution:
Just wait until the model mutex has finished processing all the current
functions. This ensures that the record has applied all its updates.
How to reproduce:
- Go to a form view with a non-editable x2m
- Add a line
- Edit a required field with a slow onchange
- Click "Save and close" before the onchange is complete
Before this commit:
The form dialog remains open and a notification appears telling us that
a required field is invalid.
After this commit:
The dialog is closed and the change has been applied.
Part-of: odoo/odoo#114024
This commit is contained in:
@@ -307,7 +307,7 @@ export class Record extends DataPoint {
|
||||
_askChanges() {
|
||||
const proms = [];
|
||||
this.model.bus.trigger("NEED_LOCAL_CHANGES", { proms });
|
||||
return Promise.all(proms);
|
||||
return Promise.all([...proms, this.model.mutex.getUnlockedDef()]);
|
||||
}
|
||||
|
||||
_checkValidity({ silent } = {}) {
|
||||
|
||||
@@ -288,10 +288,12 @@ export class StaticList extends DataPoint {
|
||||
});
|
||||
}
|
||||
|
||||
leaveEditMode({ discard, canAbandon, validate } = {}) {
|
||||
async leaveEditMode({ discard, canAbandon, validate } = {}) {
|
||||
if (this.editedRecord) {
|
||||
await this.editedRecord._askChanges(false);
|
||||
}
|
||||
return this.model.mutex.exec(async () => {
|
||||
if (this.editedRecord) {
|
||||
await this.editedRecord._askChanges();
|
||||
const isValid = this.editedRecord._checkValidity();
|
||||
if (!isValid && validate) {
|
||||
return false;
|
||||
|
||||
@@ -2024,7 +2024,7 @@ export class ListRenderer extends Component {
|
||||
* @param {HTMLElement} [params.previous]
|
||||
*/
|
||||
async sortDrop(dataRowId, { element, previous }) {
|
||||
this.props.list.leaveEditMode();
|
||||
await this.props.list.leaveEditMode();
|
||||
element.classList.remove("o_row_draggable");
|
||||
const refId = previous ? previous.dataset.id : null;
|
||||
this.resequencePromise = this.props.list.resequence(dataRowId, refId, {
|
||||
|
||||
@@ -13177,4 +13177,62 @@ QUnit.module("Fields", (hooks) => {
|
||||
assert.containsOnce(target, ".o_list_view");
|
||||
assert.verifySteps([]);
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
"one2many: save a record before the onchange is complete in a form dialog",
|
||||
async function (assert) {
|
||||
serverData.models.turtle.onchanges = {
|
||||
display_name: function () {},
|
||||
};
|
||||
|
||||
serverData.views = {
|
||||
"turtle,false,form": `
|
||||
<form>
|
||||
<field name="display_name"/>
|
||||
</form>`,
|
||||
};
|
||||
|
||||
const def = makeDeferred();
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
resId: 1,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="turtles">
|
||||
<tree>
|
||||
<field name="display_name" required="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</form>`,
|
||||
async mockRPC(route, args) {
|
||||
if (
|
||||
args.method === "onchange2" &&
|
||||
args.args[2].length === 1 &&
|
||||
args.args[2][0] === "display_name"
|
||||
) {
|
||||
await def;
|
||||
}
|
||||
},
|
||||
});
|
||||
await addRow(target);
|
||||
assert.containsOnce(target, ".modal");
|
||||
|
||||
await editInput(target, ".o_field_widget[name=display_name] input", "new name");
|
||||
await click(target, ".modal .o_form_button_save");
|
||||
assert.containsOnce(target, ".modal");
|
||||
|
||||
def.resolve();
|
||||
await nextTick();
|
||||
assert.containsNone(target, ".modal");
|
||||
assert.containsN(target, ".o_data_row", 2);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_data_row [name='display_name']")].map(
|
||||
(el) => el.textContent
|
||||
),
|
||||
["donatello", "new name"]
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user