diff --git a/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml b/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml
index 2269a570dcc..1041499adb8 100644
--- a/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml
+++ b/addons/im_livechat/static/src/views/livechat_channel_kanban/livechat_channel_kanban_menu.xml
@@ -3,7 +3,7 @@
'bottom-start'
-
+
diff --git a/addons/sale/static/src/js/product_catalog/kanban_record.js b/addons/sale/static/src/js/product_catalog/kanban_record.js
index 85971172e32..ae80a7bca66 100644
--- a/addons/sale/static/src/js/product_catalog/kanban_record.js
+++ b/addons/sale/static/src/js/product_catalog/kanban_record.js
@@ -21,7 +21,7 @@ export class ProductCatalogKanbanRecord extends KanbanRecord {
useSubEnv({
currencyId: this.props.record.context.product_catalog_currency_id,
orderId: this.props.record.context.product_catalog_order_id,
- productId: this.record.id.raw_value,
+ productId: this.props.record.resId,
addProduct: this.addProduct.bind(this),
removeProduct: this.removeProduct.bind(this),
increaseQuantity: this.increaseQuantity.bind(this),
diff --git a/addons/sale/static/src/js/product_catalog/kanban_record.xml b/addons/sale/static/src/js/product_catalog/kanban_record.xml
index a32ab8da586..c3b3c506892 100644
--- a/addons/sale/static/src/js/product_catalog/kanban_record.xml
+++ b/addons/sale/static/src/js/product_catalog/kanban_record.xml
@@ -11,7 +11,7 @@
t-att-class="{'text-bg-primary': state.quantity || props.record.productCatalogData.readOnly}">
-
diff --git a/addons/web/static/src/model/relational_model/utils.js b/addons/web/static/src/model/relational_model/utils.js
index d4e9c5f522e..518325898dd 100644
--- a/addons/web/static/src/model/relational_model/utils.js
+++ b/addons/web/static/src/model/relational_model/utils.js
@@ -503,19 +503,28 @@ export function useRecordObserver(callback) {
let alive = true;
const fct = (props) => {
const def = new Deferred();
+ let firstCall = true;
effect(
- batched(
- async (record) => {
- if (!alive) {
- // effect doesn't clean up when the component is unmounted.
- // We must do it manually.
- return;
- }
+ async (record) => {
+ if (firstCall) {
+ firstCall = false;
await callback(record);
def.resolve();
- },
- () => new Promise((resolve) => window.requestAnimationFrame(resolve))
- ),
+ } else {
+ return batched(
+ async (record) => {
+ if (!alive) {
+ // effect doesn't clean up when the component is unmounted.
+ // We must do it manually.
+ return;
+ }
+ await callback(record);
+ def.resolve();
+ },
+ () => new Promise((resolve) => window.requestAnimationFrame(resolve))
+ )(record);
+ }
+ },
[props.record]
);
return def;
diff --git a/addons/web/static/src/views/kanban/kanban_record.js b/addons/web/static/src/views/kanban/kanban_record.js
index e1aa6d10fa6..d47e56684d2 100644
--- a/addons/web/static/src/views/kanban/kanban_record.js
+++ b/addons/web/static/src/views/kanban/kanban_record.js
@@ -1,7 +1,7 @@
/** @odoo-module **/
-import { evalDomain } from "@web/core/domain";
import { ColorList } from "@web/core/colorlist/colorlist";
+import { evalDomain } from "@web/core/domain";
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { registry } from "@web/core/registry";
@@ -9,6 +9,7 @@ import { useTooltip } from "@web/core/tooltip/tooltip_hook";
import { useService } from "@web/core/utils/hooks";
import { sprintf } from "@web/core/utils/strings";
import { url } from "@web/core/utils/urls";
+import { useRecordObserver } from "@web/model/relational_model/utils";
import { Field } from "@web/views/fields/field";
import { fileTypeMagicWordMap, imageCacheKey } from "@web/views/fields/image/image_field";
import { ViewButton } from "@web/views/view_button/view_button";
@@ -24,7 +25,7 @@ import { KanbanCompiler } from "./kanban_compiler";
import { KanbanCoverImageDialog } from "./kanban_cover_image_dialog";
import { KanbanDropdownMenuWrapper } from "./kanban_dropdown_menu_wrapper";
-import { Component, onMounted, onWillUpdateProps, useRef } from "@odoo/owl";
+import { Component, onMounted, onWillUpdateProps, useRef, useState } from "@odoo/owl";
const { COLORS } = ColorList;
const formatters = registry.category("formatters");
@@ -106,7 +107,13 @@ function getValue(record, fieldName) {
}
export function getFormattedRecord(record) {
- const formattedRecord = {};
+ const formattedRecord = {
+ id: {
+ value: record.resId,
+ raw_value: record.resId,
+ },
+ };
+
for (const fieldName of record.fieldNames) {
formattedRecord[fieldName] = {
value: getValue(record, fieldName),
@@ -195,13 +202,21 @@ export class KanbanRecord extends Component {
});
}
- this.createRecordAndWidget(this.props);
+ this.dataState = useState({ record: {}, widget: {} });
+ this.createWidget(this.props);
+ onWillUpdateProps(this.createWidget);
+ useRecordObserver((record) =>
+ Object.assign(this.dataState.record, getFormattedRecord(record))
+ );
this.rootRef = useRef("root");
onMounted(() => {
// FIXME: this needs to be changed to an attribute on the root node...
this.allowGlobalClick = !!this.rootRef.el.querySelector(ALLOW_GLOBAL_CLICK);
});
- onWillUpdateProps(this.createRecordAndWidget);
+ }
+
+ get record() {
+ return this.dataState.record;
}
getFormattedValue(fieldId) {
@@ -211,20 +226,18 @@ export class KanbanRecord extends Component {
}
/**
- * Assigns both "record" and "widget" properties on the kanban record.
+ * Assigns "widget" properties on the kanban record.
*
* @param {Object} props
*/
- createRecordAndWidget(props) {
+ createWidget(props) {
const { archInfo, list } = props;
const { activeActions } = archInfo;
-
- this.record = getFormattedRecord(this.props.record);
// Widget
const deletable =
activeActions.delete && (!list.groupByField || list.groupByField.type !== "many2many");
const editable = activeActions.edit;
- this.widget = {
+ this.dataState.widget = {
deletable,
editable,
isHtmlEmpty,
@@ -357,10 +370,10 @@ export class KanbanRecord extends Component {
kanban_image: (...args) => getImageSrcFromRecordInfo(this.props.record, ...args),
luxon,
read_only_mode: this.props.readonly,
- record: this.record,
+ record: this.dataState.record,
selection_mode: this.props.forceGlobalClick,
user_context: this.user.context,
- widget: this.widget,
+ widget: this.dataState.widget,
__comp__: Object.assign(Object.create(this), { this: this }),
};
}
diff --git a/addons/web/static/src/views/kanban/kanban_renderer.xml b/addons/web/static/src/views/kanban/kanban_renderer.xml
index 75fb59f3d6a..9de68e279bf 100644
--- a/addons/web/static/src/views/kanban/kanban_renderer.xml
+++ b/addons/web/static/src/views/kanban/kanban_renderer.xml
@@ -125,7 +125,7 @@
-