diff --git a/addons/mail/static/src/widgets/form_renderer/form_renderer.js b/addons/mail/static/src/widgets/form_renderer/form_renderer.js index 86fef09c235..89868f8ee16 100644 --- a/addons/mail/static/src/widgets/form_renderer/form_renderer.js +++ b/addons/mail/static/src/widgets/form_renderer/form_renderer.js @@ -27,6 +27,12 @@ FormRenderer.include({ * This is set when arch contains `div.oe_chatter`. */ this._chatterContainerTarget = undefined; + /** + * This jQuery element will be set when rendering the form view, and + * used as a hook to insert the ChatterContainer in the right place, + * when applying the rendering into the DOM. + */ + this.$chatterContainerHook = undefined; // Do not load chatter in form view dialogs this._isFromFormViewDialog = params.isFromFormViewDialog; }, @@ -105,12 +111,12 @@ FormRenderer.include({ * @returns {jQuery.Element} */ _makeChatterContainerTarget() { - if (this._chatterContainerTarget) { - return $(this._chatterContainerTarget); + if (!this._chatterContainerTarget) { + this._chatterContainerTarget = document.createElement("div"); + this._chatterContainerTarget.classList.add("o_FormRenderer_chatterContainer"); } - const $el = $('
'); - this._chatterContainerTarget = $el[0]; - return $el; + this.$chatterContainerHook = $('
'); + return this.$chatterContainerHook; }, /** * Mount the chatter @@ -142,6 +148,18 @@ FormRenderer.include({ } return this._super(...arguments); }, + /** + * The last rendering of the form view has just been applied into the DOM, + * so we replace our chatter container hook by the actual chatter container. + * + * @override + */ + _updateView() { + this._super(...arguments); + if (this._hasChatter()) { + this.$chatterContainerHook.replaceWith(this._chatterContainerTarget); + } + }, /** * Overrides the function to render the chatter once the form view is * rendered. diff --git a/addons/mail/static/src/widgets/form_renderer/tests/form_renderer_tests.js b/addons/mail/static/src/widgets/form_renderer/tests/form_renderer_tests.js index de5e5d94d25..69a9ca1b570 100644 --- a/addons/mail/static/src/widgets/form_renderer/tests/form_renderer_tests.js +++ b/addons/mail/static/src/widgets/form_renderer/tests/form_renderer_tests.js @@ -10,8 +10,10 @@ import { } from '@mail/utils/test_utils'; import config from 'web.config'; +import fieldRegistry from 'web.field_registry'; import FormView from 'web.FormView'; -import { dom } from 'web.test_utils'; +import { dom, nextTick } from 'web.test_utils'; +import { registerCleanup } from "@web/../tests/helpers/cleanup"; const { triggerEvent } = dom; @@ -1048,6 +1050,68 @@ QUnit.test('[TECHNICAL] unfolded read more/less links should not fold on message ); }); +QUnit.test('chatter does not flicker when the form view is re-rendered', async function (assert) { + this.data['res.partner'].records.push( + { display_name: "first partner", id: 11 }, + { display_name: "second partner", id: 12 } + ); + + // define an asynchronous field and use it in the form to ease testing + let def; + const FieldChar = fieldRegistry.get("char"); + const AsyncWidget = FieldChar.extend({ + willStart() { + return Promise.resolve(def); + }, + }); + fieldRegistry.add("async_widget", AsyncWidget); + registerCleanup(() => { + delete fieldRegistry.map.async_widget; + }); + + await this.createView({ + data: this.data, + hasView: true, + // View params + View: FormView, + model: 'res.partner', + arch: ` +
+ + + +
+
+ `, + viewOptions: { + currentId: 11, + ids: [11, 12], + }, + }); + assert.strictEqual( + document.querySelectorAll(`.o_Chatter`).length, + 1, + "there should be a chatter" + ); + def = makeDeferred(); + document.querySelector('.o_pager_next').click(); + await nextTick(); + + assert.strictEqual( + document.querySelectorAll(`.o_Chatter`).length, + 1, + "there should be a chatter" + ); + def.resolve(); + await nextTick(); + + assert.strictEqual( + document.querySelectorAll(`.o_Chatter`).length, + 1, + "there should be a chatter" + ); +}); + }); }); }); diff --git a/addons/project/static/src/project_sharing/views/form/renderer.js b/addons/project/static/src/project_sharing/views/form/renderer.js index f4acf457a66..614bb776f3a 100644 --- a/addons/project/static/src/project_sharing/views/form/renderer.js +++ b/addons/project/static/src/project_sharing/views/form/renderer.js @@ -25,30 +25,7 @@ export default FormRenderer.extend({ project_sharing_id: session.project_id, }; }, - _makeChatterContainerTarget() { - const $el = $('
'); - this._chatterContainerTarget = $el[0]; - return $el; - }, _mountChatterContainerComponent() { this._chatterContainerComponent.appendTo(this._chatterContainerTarget); }, - _renderNode(node) { - if (node.tag === 'div' && node.attrs.class === 'oe_project_sharing_chatter') { - let isVisible = true; - if (node.attrs.modifiers && node.attrs.modifiers.invisible) { - const record = this._getRecord(this.state.id); - if (record) { - isVisible = !record.evalModifiers(node.attrs.modifiers).invisible; - } - } - if (isVisible) { - if (this._isFromFormViewDialog) { - return $('
'); - } - return this._makeChatterContainerTarget(); - } - } - return this._super(...arguments); - }, });