From e61454f148583c90fca625de75fce85b5d0129c8 Mon Sep 17 00:00:00 2001 From: Aaron Bohy Date: Thu, 20 Apr 2017 11:13:28 +0200 Subject: [PATCH] [FIX] web: BasicRenderer: don't reset this.defs too soon The 'defs' attribute of the BasicRenderer is used to push the rendering deferred of asynchronous fields. It is set to an empty array before the rendering, and for each asynchronous field, its deferred is pushed in the array, so that the renderer can wait for all its fields to be rendered (no flickering). The function '_applyModifiers' is called during the whole view rendering (for each field in the view), and when some fields change, as the modifiers are then re-evaluated. As it is called during the whole view rendering, it can't delete the 'defs' attribute, otherwise it will crash if one of the remaining fields in the view uses an asynchronous widget (trying to push a deferred in an undefined variable). This rev. moves the deletion of 'defs' to the function that is called when all modifiers are re-evaluated and applied. --- .../src/js/views/basic/basic_renderer.js | 15 +++++-------- addons/web/static/tests/views/form_tests.js | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index a18a82e5745..dd0f59a4176 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -176,23 +176,17 @@ var BasicRenderer = AbstractRenderer.extend({ * @param {Object} modifiersData * @param {Object} record * @param {Object} [element] - do the update only on this element if given - * @returns {Deferred} resolved once finished */ _applyModifiers: function (modifiersData, record, element) { var self = this; - var defs = []; var modifiers = modifiersData.evaluatedModifiers[record.id] || {}; - this.defs = defs; // Potentially filled by widget rerendering if (element) { _apply(element); } else { // Clone is necessary as the list might change during _.each _.each(_.clone(modifiersData.elementsByRecord[record.id]), _apply); } - delete this.defs; - - return $.when.apply($, defs); function _apply(element) { // If the view is in edit mode and that a widget have to switch @@ -540,10 +534,13 @@ var BasicRenderer = AbstractRenderer.extend({ _updateAllModifiers: function (record) { var self = this; - var defs = _.flatten(_.map(this.allModifiersData, function (modifiersData) { + var defs = []; + this.defs = defs; // Potentially filled by widget rerendering + _.each(this.allModifiersData, function (modifiersData) { self._computeModifiers(modifiersData, record); - return self._applyModifiers(modifiersData, record); - })); + self._applyModifiers(modifiersData, record); + }); + delete this.defs; return $.when.apply($, defs); }, diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index ce2f3b37f29..804ac737ef7 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -3112,5 +3112,27 @@ QUnit.module('Views', { "the stat button should contain a span with the string attribute value"); form.destroy(); }); + + QUnit.test('renderer waits for asynchronous fields rendering', function (assert) { + assert.expect(1); + var done = assert.async(); + + testUtils.createAsyncView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '', + res_id: 1, + }).then(function (form) { + assert.strictEqual(form.$('.ace_editor').length, 1, + "should have waited for ace to load its dependencies"); + form.destroy(); + done(); + }); + }); }); });