[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
This commit is contained in:
abd-msyukyu-odoo
2023-12-07 15:53:07 +00:00
parent 8e72a2f4b4
commit fbac26be7c
2 changed files with 85 additions and 12 deletions
+17 -12
View File
@@ -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);
}
});
}
@@ -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`
<a id="next" t-on-click="next">NEXT</a>
<Record resId="state.currentId" resModel="'partner'" fieldNames="['foo']" fields="fields" values="values" t-slot-scope="data">
<Field name="'foo'" record="data.record"/>
</Record>
`;
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);
});
});