From fbac26be7cde9ee9ffa00e3510ef9677c2420a8e Mon Sep 17 00:00:00 2001 From: abd-msyukyu-odoo Date: Tue, 28 Nov 2023 19:18:11 +0100 Subject: [PATCH] [FIX] web: get next config for model loaded with values In `web_hierarchy`, the model is always loaded with values. However, when a record (component) props are updated, its resId can change (i.e. if the ordering in the hierarchy view changes), therefore not only the `root` of the model should be updated with the provided values, but the config should be reevaluated as well since some record (datapoint) getters use it. task-3562116 Part-of: odoo/odoo#143941 --- addons/web/static/src/model/record.js | 29 ++++---- addons/web/static/tests/views/record_tests.js | 68 +++++++++++++++++++ 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/addons/web/static/src/model/record.js b/addons/web/static/src/model/record.js index d12623dd286..302de461d84 100644 --- a/addons/web/static/src/model/record.js +++ b/addons/web/static/src/model/record.js @@ -12,10 +12,9 @@ class StandaloneRelationalModel extends RelationalModel { load(params = {}) { if (params.values) { const data = params.values; - if (params.mode) { - this.config.mode = params.mode; - } - this.root = this._createRoot(this.config, data); + const config = this._getNextConfig(this.config, params); + this.root = this._createRoot(config, data); + this.config = config; return; } return super.load(params); @@ -50,7 +49,7 @@ class _Record extends Component { modelServices.orm = this.orm; this.model = useState(new StandaloneRelationalModel(this.env, modelParams, modelServices)); - const loadWithValues = async (values) => { + const prepareLoadWithValues = async (values) => { values = pick(values, ...Object.keys(modelParams.config.activeFields)); const proms = []; for (const fieldName in values) { @@ -113,20 +112,26 @@ class _Record extends Component { } await Promise.all(proms); } - return this.model.load({ values }); + return values; }; - onWillStart(() => { + onWillStart(async () => { if (this.props.values) { - return loadWithValues(this.props.values); + const values = await prepareLoadWithValues(this.props.values); + return this.model.load({ values }); } else { return this.model.load(); } }); - onWillUpdateProps((nextProps) => { + onWillUpdateProps(async (nextProps) => { + const params = {}; + if (nextProps.info.resId !== this.model.root.resId) { + params.resId = nextProps.info.resId; + } if (nextProps.values) { - return loadWithValues(nextProps.values); - } else if (nextProps.info.resId !== this.model.root.resId) { - return this.model.load({ resId: nextProps.info.resId }); + params.values = await prepareLoadWithValues(nextProps.values); + } + if (Object.keys(params).length) { + return this.model.load(params); } }); } diff --git a/addons/web/static/tests/views/record_tests.js b/addons/web/static/tests/views/record_tests.js index 450182da35e..1bd0cf95481 100644 --- a/addons/web/static/tests/views/record_tests.js +++ b/addons/web/static/tests/views/record_tests.js @@ -607,4 +607,72 @@ QUnit.module("Record Component", (hooks) => { assert.strictEqual(increment.textContent, "2"); assert.strictEqual(field.textContent, "blop"); }); + + QUnit.test("can switch records with values", async (assert) => { + class Parent extends Component { + setup() { + this.fields = { + foo: { + name: "foo", + type: "char", + }, + bar: { + name: "bar", + type: "boolean", + }, + }; + this.values = { + foo: "abc", + bar: true, + }; + this.state = useState({ currentId: 99 }); + } + + next() { + this.state.currentId = 100; + this.values = { + foo: "def", + bar: false, + }; + } + } + Parent.components = { Record, Field }; + Parent.template = xml` + + + + + `; + let _record; + patchWithCleanup(Record.components._Record.prototype, { + setup() { + super.setup(); + _record = this; + }, + }); + + await mount(Parent, target, { + env: await makeTestEnv({ + serverData, + mockRPC(route) { + assert.step(route); + }, + }), + }); + // No load since the values are provided to the record + assert.verifySteps([]); + const field = target.querySelector("div[name='foo']"); + // First values are loaded + assert.strictEqual(field.textContent, "abc"); + // Verify that the underlying _Record Model root has the specified resId + assert.strictEqual(_record.model.root.resId, 99); + + await click(target.querySelector("#next")); + // Still no load. + assert.verifySteps([]); + // Second values are loaded + assert.strictEqual(field.textContent, "def"); + // Verify that the underlying _Record Model root has the updated resId + assert.strictEqual(_record.model.root.resId, 100); + }); });