[FIX] web: basic_model: applyOnChange with 2 consecutive one2many
The problem is generally due to the use of `var`, this one https://github.com/odoo-dev/odoo/blob/58a046d2146e884d467cde827f89fa603ed98a3b/addons/web/static/src/js/views/basic/basic_model.js#L1780 followed by an asynchronous call to a function using it We can therefore summarize the part of the `_applyOnChange` function that interests us by ```js for () { if (field. type === 'one2many' || field. type === 'many2many') { var list; ... //using list ... promiseFunction(list).then(function(){ //using list }) } } ``` In the case where we have two one2many which follow each other, this scenario occurs: - `list` is initially the first o2m - the `promiseFunction` is called with `list` (first o2m) - before the promise is resolved the loop continues - `list` is `Promise.then()` the second o2m - the first call to `promiseFunction` with `list` (first o2m) is done - we enter in `Promise.then()` - `list` is currently worth the value of the second o2m because `list` is a `var` - the second call to `promiseFunction` with `list` is finished - we enter the `Promise.then()` - `list` is currently worth the value of the second o2m because `list` is a `var` Result: `Promise.then()` is called twice with the first o2m and never with the second We can see what happened with this code example: ```js const array = ["a", "b"]; const asyncRead = async(value) => { console.log("async function arg", value) setTimeout(()=>{ return Promise. resolve(value); }, 100) } const forFunction = () => { for (let i = 0; i < array.length; i++){ var list = array[i]; asyncRead(list).then(function (){ console.log("then async function arg", list) }) } } forFunction() /* async function arg a async function arg b then async function arg b then async function arg b */ ``` While if: We use `let` by replacing `var list = array[i];` with `let list = array[i];` OR We force the use of `Promise.resolve()` argument by replacing `.then(function (){}` with `.then(function (list){}` We will get: ```js /* async function arg a async function arg b then async function arg a then async function arg b */ ``` opw-2694855 closes odoo/odoo#89160 X-original-commit: 99cb2f52e109ccf94ac8bd735cd776e84ef04260 Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
This commit is contained in:
committed by
Achraf (abz)
parent
75c4468b9a
commit
6af8b7f95e
@@ -1909,7 +1909,7 @@ var BasicModel = AbstractModel.extend({
|
||||
});
|
||||
}
|
||||
});
|
||||
var def = self._readUngroupedList(list).then(function () {
|
||||
var def = self._readUngroupedList(list).then(function (list) {
|
||||
var x2ManysDef = self._fetchX2ManysBatched(list);
|
||||
var referencesDef = self._fetchReferencesBatched(list);
|
||||
return Promise.all([x2ManysDef, referencesDef]);
|
||||
|
||||
@@ -4178,6 +4178,56 @@ QUnit.module('relational_fields', {
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
QUnit.test('Check onchange with two consecutive many2one', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.data.product.fields.product_partner_ids = { string: "User", type: 'one2many', relation: 'partner' };
|
||||
this.data.product.records[0].product_partner_ids = [1];
|
||||
this.data.product.records[1].product_partner_ids = [2];
|
||||
this.data.turtle.fields.product_ids = { string: "Product", type: "one2many", relation: 'product' };
|
||||
this.data.turtle.fields.user_ids = { string: "Product", type: "one2many", relation: 'user' };
|
||||
this.data.turtle.onchanges = {
|
||||
turtle_trululu: function (record) {
|
||||
record.product_ids = [37];
|
||||
record.user_ids = [17, 19];
|
||||
},
|
||||
};
|
||||
var form = await createView({
|
||||
View: FormView,
|
||||
model: 'turtle',
|
||||
data: this.data,
|
||||
arch:
|
||||
'<form string="Turtles">' +
|
||||
'<field string="Product" name="turtle_trululu"/>' +
|
||||
'<field readonly="1" string="Related field" name="product_ids">' +
|
||||
'<tree>' +
|
||||
'<field widget="many2many_tags" name="product_partner_ids"/>' +
|
||||
'</tree>' +
|
||||
'</field>' +
|
||||
'<field readonly="1" string="Second related field" name="user_ids">' +
|
||||
'<tree>' +
|
||||
'<field widget="many2many_tags" name="partner_ids"/>' +
|
||||
'</tree>' +
|
||||
'</field>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
});
|
||||
|
||||
await testUtils.form.clickEdit(form);
|
||||
await testUtils.fields.many2one.clickOpenDropdown("turtle_trululu");
|
||||
await testUtils.fields.many2one.searchAndClickItem('turtle_trululu', {search: 'first record'});
|
||||
|
||||
const getElementTextContent = name => [...document.querySelectorAll(`.o_field_many2manytags[name="${name}"] .badge.o_tag_color_0 > span`)]
|
||||
.map(x=>x.textContent);
|
||||
assert.deepEqual(
|
||||
getElementTextContent('product_partner_ids'),
|
||||
['first record'],
|
||||
"should have the correct value in the many2many tag widget");
|
||||
assert.deepEqual(
|
||||
getElementTextContent('partner_ids'),
|
||||
['first record', 'second record'],
|
||||
"should have the correct values in the many2many tag widget");
|
||||
form.destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user