diff --git a/addons/account/static/src/components/account_payment_field/account_payment.xml b/addons/account/static/src/components/account_payment_field/account_payment.xml index 344a24c9038..2fc8b32cee9 100644 --- a/addons/account/static/src/components/account_payment_field/account_payment.xml +++ b/addons/account/static/src/components/account_payment_field/account_payment.xml @@ -4,15 +4,16 @@
- + +
- +
- + - + - + diff --git a/addons/account/static/src/components/account_payment_field/account_payment_field.js b/addons/account/static/src/components/account_payment_field/account_payment_field.js index a38a11615aa..543031fce5a 100644 --- a/addons/account/static/src/components/account_payment_field/account_payment_field.js +++ b/addons/account/static/src/components/account_payment_field/account_payment_field.js @@ -10,7 +10,7 @@ import { parseDate, formatDate } from "@web/core/l10n/dates"; import { formatMonetary } from "@web/views/fields/formatters"; import { standardFieldProps } from "@web/views/fields/standard_field_props"; -const { Component, onWillUpdateProps } = owl; +const { Component } = owl; class AccountPaymentPopOver extends Component {} AccountPaymentPopOver.props = { @@ -26,30 +26,31 @@ export class AccountPaymentField extends Component { this.popover = usePopover(AccountPaymentPopOver, { position }); this.orm = useService("orm"); this.action = useService("action"); - - this.formatData(this.props); - onWillUpdateProps((nextProps) => this.formatData(nextProps)); } - formatData(props) { - const info = props.record.data[props.name] || { + getInfo() { + const info = this.props.record.data[this.props.name] || { content: [], outstanding: false, title: "", move_id: this.props.record.resId, }; - for (let [key, value] of Object.entries(info.content)) { + for (const [key, value] of Object.entries(info.content)) { value.index = key; - value.amount_formatted = formatMonetary(value.amount, { currencyId: value.currency_id }); + value.amount_formatted = formatMonetary(value.amount, { + currencyId: value.currency_id, + }); if (value.date) { // value.date is a string, parse to date and format to the users date format value.date = formatDate(parseDate(value.date)); } } - this.lines = info.content; - this.outstanding = info.outstanding; - this.title = info.title; - this.move_id = info.move_id; + return { + lines: info.content, + outstanding: info.outstanding, + title: info.title, + moveId: info.move_id, + }; } onInfoClick(ev, idx) { @@ -61,8 +62,8 @@ export class AccountPaymentField extends Component { }); } - async assignOutstandingCredit(id) { - await this.orm.call(this.props.record.resModel, 'js_assign_outstanding_line', [this.move_id, id], {}); + async assignOutstandingCredit(moveId, id) { + await this.orm.call(this.props.record.resModel, 'js_assign_outstanding_line', [moveId, id], {}); await this.props.record.model.root.load(); } diff --git a/addons/account/static/src/components/account_resequence/account_resequence.xml b/addons/account/static/src/components/account_resequence/account_resequence.xml index a18065b84b5..2578c6552af 100644 --- a/addons/account/static/src/components/account_resequence/account_resequence.xml +++ b/addons/account/static/src/components/account_resequence/account_resequence.xml @@ -2,15 +2,16 @@ -
Add + t-on-click.prevent="() => this.assignOutstandingCredit(info.moveId, line.id)">Add
+ +
- - + +
Date Before After
diff --git a/addons/account/static/src/components/account_resequence/account_resequence_field.js b/addons/account/static/src/components/account_resequence/account_resequence_field.js index 4f81c146357..85c62be3b43 100644 --- a/addons/account/static/src/components/account_resequence/account_resequence_field.js +++ b/addons/account/static/src/components/account_resequence/account_resequence_field.js @@ -2,20 +2,16 @@ import { registry } from "@web/core/registry"; -const { Component, onWillUpdateProps } = owl; +const { Component } = owl; class ChangeLine extends Component {} ChangeLine.template = "account.ResequenceChangeLine"; ChangeLine.props = ["changeLine", "ordering"]; class ShowResequenceRenderer extends Component { - setup() { - this.formatData(this.props); - onWillUpdateProps((nextProps) => this.formatData(nextProps)); - } - - formatData(props) { - this.data = props.record.data[props.name] ? JSON.parse(props.record.data[props.name]) : { changeLines: [], ordering: "date" }; + getValue() { + const value = this.props.record.data[this.props.name]; + return value ? JSON.parse(value) : { changeLines: [], ordering: "date" }; } } ShowResequenceRenderer.template = "account.ResequenceRenderer"; diff --git a/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js b/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js index 8c1860d5c39..37e546f2652 100644 --- a/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js +++ b/addons/account/static/src/components/autosave_many2many_tags/autosave_many2many_tags.js @@ -1,16 +1,13 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; +import { useRecordObserver } from "@web/model/relational_model/utils"; import { Many2ManyTagsField, many2ManyTagsField } from "@web/views/fields/many2many_tags/many2many_tags_field"; -const { onWillUpdateProps } = owl; - export class AutosaveMany2ManyTagsField extends Many2ManyTagsField { setup() { super.setup(); - onWillUpdateProps((nextProps) => this.willUpdateProps(nextProps)); - this.lastBalance = this.props.record.data.balance; this.lastAccount = this.props.record.data.account_id; this.lastPartner = this.props.record.data.partner_id; @@ -20,6 +17,7 @@ export class AutosaveMany2ManyTagsField extends Many2ManyTagsField { super_update(recordlist); this._saveOnUpdate(); }; + useRecordObserver(this.onRecordChange.bind(this)); } async deleteTag(id) { @@ -27,8 +25,8 @@ export class AutosaveMany2ManyTagsField extends Many2ManyTagsField { await this._saveOnUpdate(); } - willUpdateProps(nextProps) { - const line = this.props.record.data; + onRecordChange(record) { + const line = record.data; if (line.tax_ids.records.length > 0) { if (line.balance !== this.lastBalance || line.account_id[0] !== this.lastAccount[0] @@ -36,7 +34,7 @@ export class AutosaveMany2ManyTagsField extends Many2ManyTagsField { this.lastBalance = line.balance; this.lastAccount = line.account_id; this.lastPartner = line.partner_id; - this._saveOnUpdate(); + return record.model.root.save(); } } } diff --git a/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js b/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js index 77021996ae2..28fcc7d0d8c 100644 --- a/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js +++ b/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.js @@ -2,7 +2,7 @@ import { registry } from "@web/core/registry"; -const { Component, onWillUpdateProps } = owl; +const { Component } = owl; class ListItem extends Component {} ListItem.template = "account.GroupedItemTemplate"; @@ -14,14 +14,10 @@ ListGroup.components = { ListItem }; ListGroup.props = ["group_vals", "options"]; class ShowGroupedList extends Component { - setup() { - this.formatData(this.props); - onWillUpdateProps((nextProps) => this.formatData(nextProps)); - } - - formatData(props) { - this.data = props.record.data[props.name] - ? JSON.parse(props.record.data[props.name]) + getValue() { + const value = this.props.record.data[this.props.name]; + return value + ? JSON.parse(value) : { groups_vals: [], options: { discarded_number: "", columns: [] } }; } } diff --git a/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.xml b/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.xml index 12ce877604e..b4faa939593 100644 --- a/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.xml +++ b/addons/account/static/src/components/grouped_view_widget/grouped_view_widget.xml @@ -1,18 +1,19 @@ - + +
- + - - + +
- - are not shown in the preview + + are not shown in the preview diff --git a/addons/mass_mailing/static/src/js/mass_mailing_html_field.js b/addons/mass_mailing/static/src/js/mass_mailing_html_field.js index beafe5a910d..24e8f24d42e 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_html_field.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_html_field.js @@ -2,6 +2,7 @@ import { registry } from "@web/core/registry"; import { _t } from "@web/core/l10n/translation"; +import { useRecordObserver } from "@web/model/relational_model/utils"; import { standardFieldProps } from "@web/views/fields/standard_field_props"; import { initializeDesignTabCss } from "@mass_mailing/js/mass_mailing_design_constants" import { toInline, getCSSRules } from "@web_editor/js/backend/convert_inline"; @@ -15,11 +16,7 @@ import { getRangePosition } from '@web_editor/js/editor/odoo-editor/src/utils/ut import { MassMailingWysiwyg } from '@mass_mailing/js/mass_mailing_wysiwyg'; import { utils as uiUtils } from "@web/core/ui/ui_service"; -const { - useSubEnv, - onWillUpdateProps, - status, -} = owl; +const { useSubEnv, status } = owl; export class MassMailingHtmlField extends HtmlField { static props = { @@ -44,9 +41,9 @@ export class MassMailingHtmlField extends HtmlField { this.rpc = useService('rpc'); this.dialog = useService('dialog'); - onWillUpdateProps(() => { - if (this.props.record.data.mailing_model_id && this.wysiwyg) { - this._hideIrrelevantTemplates(); + useRecordObserver((record) => { + if (record.data.mailing_model_id && this.wysiwyg) { + this._hideIrrelevantTemplates(record); } }); } @@ -453,7 +450,7 @@ export class MassMailingHtmlField extends HtmlField { this.wysiwyg.$iframeBody.find('.iframe-utils-zone').removeClass('d-none'); if (this.env.mailingFilterTemplates && this.wysiwyg) { - this._hideIrrelevantTemplates(); + this._hideIrrelevantTemplates(this.props.record); } } _getCodeViewEl() { @@ -474,10 +471,10 @@ export class MassMailingHtmlField extends HtmlField { * * @private */ - _hideIrrelevantTemplates() { + _hideIrrelevantTemplates(record) { const iframeContent = this.wysiwyg.$iframe.contents(); - const mailing_model_id = this.props.record.data.mailing_model_id[0]; + const mailing_model_id = record.data.mailing_model_id[0]; iframeContent .find(`.o_mail_template_preview[model-id!="${mailing_model_id}"]`) .addClass('d-none') @@ -496,7 +493,7 @@ export class MassMailingHtmlField extends HtmlField { iframeContent.find('.o_mailing_template_preview_wrapper').removeClass('d-none'); } else { iframeContent.find('.o_mailing_template_message').removeClass('d-none'); - iframeContent.find('.o_mailing_template_message span').text(this.props.record.data.mailing_model_id[1]); + iframeContent.find('.o_mailing_template_message span').text(record.data.mailing_model_id[1]); iframeContent.find('.o_mailing_template_preview_wrapper').addClass('d-none'); } } diff --git a/addons/mrp/static/src/widgets/timer.js b/addons/mrp/static/src/widgets/timer.js index d878ed4a49d..51b9e202c90 100644 --- a/addons/mrp/static/src/widgets/timer.js +++ b/addons/mrp/static/src/widgets/timer.js @@ -95,10 +95,6 @@ class MrpTimerField extends Component { parse: (v) => parseFloatTime(v), }); - // duration is expected to be given in minutes - this.duration = this.props.record.data[this.props.name]; - this.ongoing = this.props.record.data.is_user_working; - onWillStart(async () => { if ( !this.props.record.model.useSampleModel && @@ -111,10 +107,6 @@ class MrpTimerField extends Component { ); } }); - onWillUpdateProps((nextProps) => { - this.ongoing = nextProps.record.data.is_user_working; - this.duration = nextProps.record.data[nextProps.name]; - }); onWillDestroy(() => clearTimeout(this.timer)); } @@ -125,6 +117,15 @@ class MrpTimerField extends Component { } return formatMinutes(this.duration); } + + get ongoing() { + return this.props.record.data.is_user_working; + } + + get duration() { + // duration is expected to be given in minutes + return this.props.record.data[this.props.name]; + } } export const mrpTimerField = { diff --git a/addons/stock/static/src/widgets/json_widget.js b/addons/stock/static/src/widgets/json_widget.js index 909eabaa2e1..cd5381def44 100644 --- a/addons/stock/static/src/widgets/json_widget.js +++ b/addons/stock/static/src/widgets/json_widget.js @@ -4,15 +4,11 @@ import { registry } from "@web/core/registry"; import { _t } from "@web/core/l10n/translation"; import { useService } from "@web/core/utils/hooks"; -const { Component, onWillStart, onWillUpdateProps } = owl; +const { Component, onWillStart } = owl; export class JsonPopOver extends Component { - - setup(){ - this.jsonValue = JSON.parse(this.props.record.data[this.props.name]); - onWillUpdateProps(nextProps => { - this.jsonValue = JSON.parse(nextProps.record.data[nextProps.name]); - }); + get jsonValue() { + return JSON.parse(this.props.record.data[this.props.name]); } } diff --git a/addons/web/static/src/views/fields/image_url/image_url_field.js b/addons/web/static/src/views/fields/image_url/image_url_field.js index e6b7f4a0be1..b4950c8cd2e 100644 --- a/addons/web/static/src/views/fields/image_url/image_url_field.js +++ b/addons/web/static/src/views/fields/image_url/image_url_field.js @@ -1,11 +1,12 @@ /** @odoo-module **/ +import { _t } from "@web/core/l10n/translation"; import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; -import { _t } from "@web/core/l10n/translation"; import { standardFieldProps } from "../standard_field_props"; -import { Component, onWillUpdateProps, useState } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; +import { useRecordObserver } from "@web/model/relational_model/utils"; export class ImageUrlField extends Component { static template = "web.ImageUrlField"; @@ -23,10 +24,8 @@ export class ImageUrlField extends Component { src: this.props.record.data[this.props.name], }); - onWillUpdateProps((nextProps) => { - if (this.props.record.data[this.props.name] !== nextProps.record.data[nextProps.name]) { - this.state.value = nextProps.record.data[nextProps.name]; - } + useRecordObserver((record) => { + this.state.src = record.data[this.props.name]; }); } diff --git a/addons/web/static/tests/views/fields/image_url_field_tests.js b/addons/web/static/tests/views/fields/image_url_field_tests.js index 274562f0b5b..37b291a3518 100644 --- a/addons/web/static/tests/views/fields/image_url_field_tests.js +++ b/addons/web/static/tests/views/fields/image_url_field_tests.js @@ -1,7 +1,13 @@ /** @odoo-module **/ import { KanbanController } from "@web/views/kanban/kanban_controller"; -import { click, getFixture, patchWithCleanup } from "@web/../tests/helpers/utils"; +import { + click, + editInput, + getFixture, + nextTick, + patchWithCleanup, +} from "@web/../tests/helpers/utils"; import { makeView, setupViewRegistries } from "@web/../tests/views/helpers"; let serverData; @@ -238,4 +244,39 @@ QUnit.module("Fields", (hooks) => { "the widget should not contain an image" ); }); + + QUnit.test("onchange update image fields", async function (assert) { + const srcTest = "/my/test/src"; + serverData.models.partner.onchanges = { + display_name(record) { + record.foo = srcTest; + }, + }; + + await makeView({ + serverData, + type: "form", + resModel: "partner", + arch: ` +
+ + + `, + resId: 1, + }); + + assert.strictEqual( + target.querySelector('div[name="foo"] > img').dataset.src, + FR_FLAG_URL, + "the image should have the correct src" + ); + + await editInput(target, '[name="display_name"] input', "test"); + await nextTick(); + assert.strictEqual( + target.querySelector('div[name="foo"] > img').dataset.src, + srcTest, + "the image should have the onchange src" + ); + }); });