From 475f8aa2c6c049bb5e6363e21741334e5c01d879 Mon Sep 17 00:00:00 2001 From: Lucas Perais Date: Fri, 23 Dec 2022 09:00:13 +0000 Subject: [PATCH] [IMP] web: add a onRecordChanged prop to the Record component Before this commit, there was no way to instanciate a Record component and be able to handle changes occuring in that record. After this commit, a simple props is added, making this use case possible. closes odoo/odoo#109846 Signed-off-by: Aaron Bohy (aab) --- addons/web/static/src/views/record.js | 38 ++++++++++++--- addons/web/static/tests/views/record_tests.js | 47 +++++++++++++++++++ 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/addons/web/static/src/views/record.js b/addons/web/static/src/views/record.js index abc652fe4df..c46c9f4db2e 100644 --- a/addons/web/static/src/views/record.js +++ b/addons/web/static/src/views/record.js @@ -5,21 +5,17 @@ import { useModel } from "@web/views/model"; import { RelationalModel } from "@web/views/relational_model"; import { Component, xml, onWillStart, onWillUpdateProps } from "@odoo/owl"; +const defaultActiveField = { attrs: {}, options: {}, domain: "[]", string: "" }; + class _Record extends Component { setup() { - const activeFields = - this.props.info.activeFields || - Object.fromEntries( - this.props.info.fieldNames.map((f) => [f, { attrs: {}, options: {}, domain: "[]" }]) - ); - this.model = useModel(RelationalModel, { resId: this.props.info.resId, resModel: this.props.info.resModel, fields: this.props.fields, viewMode: "form", rootType: "record", - activeFields, + activeFields: this.getActiveFields(), mode: this.props.info.mode === "edit" ? "edit" : undefined, initialValues: this.props.info.initialValues, }); @@ -29,9 +25,36 @@ class _Record extends Component { mode: nextProps.info.mode, }); }); + + if (this.props.info.onRecordChanged) { + const load = this.model.load; + this.model.load = async (...args) => { + const res = await load.call(this.model, ...args); + const root = this.model.root; + root.onChanges = async () => { + const changes = root.getChanges(); + this.props.info.onRecordChanged(root, changes); + }; + return res; + }; + } + } + + getActiveFields() { + if (this.props.info.activeFields) { + const activeFields = {}; + for (const [fName, fInfo] of Object.entries(this.props.info.activeFields)) { + activeFields[fName] = { ...defaultActiveField, ...fInfo }; + } + return activeFields; + } + return Object.fromEntries( + this.props.info.fieldNames.map((f) => [f, { ...defaultActiveField }]) + ); } } _Record.template = xml``; +_Record.props = ["slots", "info", "fields"]; export class Record extends Component { setup() { @@ -61,4 +84,5 @@ Record.props = [ "resId?", "mode?", "initialValues?", + "onRecordChanged?", ]; diff --git a/addons/web/static/tests/views/record_tests.js b/addons/web/static/tests/views/record_tests.js index 223e411bb87..a9dad462d48 100644 --- a/addons/web/static/tests/views/record_tests.js +++ b/addons/web/static/tests/views/record_tests.js @@ -7,6 +7,7 @@ import { click, getFixture, mount } from "../helpers/utils"; import { setupViewRegistries } from "../views/helpers"; import { Component, xml, useState } from "@odoo/owl"; +import { editInput } from "@web/../tests/helpers/utils"; let serverData; let target; @@ -183,4 +184,50 @@ QUnit.module("Record Component", (hooks) => { assert.verifySteps([]); assert.strictEqual(target.querySelector(".o_field_widget input").value, "abc"); }); + + QUnit.test("provides a way to handle changes in the record", async function (assert) { + class Parent extends Component { + setup() { + this.fields = { + foo: { + name: "foo", + type: "char", + }, + bar: { + name: "bar", + type: "boolean", + }, + }; + this.values = { + foo: "abc", + bar: true, + }; + } + + onRecordChanged(record, changes) { + assert.step("record changed"); + assert.strictEqual(record.model.constructor.name, "RelationalModel"); + assert.deepEqual(changes, { foo: "753" }); + } + } + Parent.components = { Record, Field }; + Parent.template = xml` + + + + `; + + await mount(Parent, target, { + env: await makeTestEnv({ + serverData, + mockRPC(route) { + assert.step(route); + }, + }), + }); + assert.strictEqual(target.querySelector("[name='foo'] input").value, "abc"); + await editInput(target, "[name='foo'] input", "753"); + assert.verifySteps(["record changed"]); + assert.strictEqual(target.querySelector("[name='foo'] input").value, "753"); + }); });