diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js
index 6cc8a3c8143..bb945d6fbb0 100644
--- a/addons/web/static/src/js/views/abstract_view.js
+++ b/addons/web/static/src/js/views/abstract_view.js
@@ -138,21 +138,23 @@ var AbstractView = Class.extend({
*/
getController: function (parent) {
var self = this;
+ // check if a model already exists, as if not, one will be created and
+ // we'll have to set the controller as its parent
+ var alreadyHasModel = !!this.model;
return $.when(this._loadData(parent), ajax.loadLibs(this)).then(function () {
- var model = self.getModel();
- var state = model.get(arguments[0]);
+ var state = self.model.get(arguments[0]);
var renderer = self.getRenderer(parent, state);
var Controller = self.Controller || self.config.Controller;
var controllerParams = _.extend({
initialState: state,
}, self.controllerParams);
- var controller = new Controller(parent, model, renderer, controllerParams);
+ var controller = new Controller(parent, self.model, renderer, controllerParams);
renderer.setParent(controller);
- if (!self.model) {
+ if (!alreadyHasModel) {
// if we have a model, it already has a parent. Otherwise, we
// set the controller, so the rpcs from the model actually work
- model.setParent(controller);
+ self.model.setParent(controller);
}
return controller;
});
diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js
index 2ff472335ef..15478d6dff6 100644
--- a/addons/web/static/tests/helpers/test_utils.js
+++ b/addons/web/static/tests/helpers/test_utils.js
@@ -174,6 +174,7 @@ function createAsyncView(params) {
return view.getController(widget).then(function (view) {
// override the view's 'destroy' so that it calls 'destroy' on the widget
// instead, as the widget is the parent of the view and the mockServer.
+ view.__destroy = view.destroy;
view.destroy = function () {
// remove the override to properly destroy the view and its children
// when it will be called the second time (by its parent)
diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js
index b6cbcd7e03f..df8495b1a18 100644
--- a/addons/web/static/tests/views/calendar_tests.js
+++ b/addons/web/static/tests/views/calendar_tests.js
@@ -4,6 +4,7 @@ odoo.define('web.calendar_tests', function (require) {
var CalendarView = require('web.CalendarView');
var CalendarRenderer = require('web.CalendarRenderer');
var fieldUtils = require('web.field_utils');
+var mixins = require('web.mixins');
var testUtils = require('web.test_utils');
var session = require('web.session');
@@ -1650,6 +1651,64 @@ QUnit.module('Views', {
calendar.destroy();
});
+
+ QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ assert.expect(1);
+
+ var instanceNumber = 0;
+ var initWidget = mixins.ParentedMixin.init;
+ mixins.ParentedMixin.init = function () {
+ instanceNumber++;
+ return initWidget.apply(this, arguments);
+ };
+ var destroyWidget = mixins.ParentedMixin.destroy;
+ mixins.ParentedMixin.destroy = function () {
+ if (!this.isDestroyed()) {
+ instanceNumber--;
+ }
+ return destroyWidget.apply(this, arguments);
+ };
+
+ var params = {
+ View: CalendarView,
+ model: 'event',
+ data: this.data,
+ arch:
+ ''+
+ ''+
+ ''+
+ ''+
+ '',
+ archs: archs,
+ viewOptions: {
+ initialDate: initialDate,
+ },
+ };
+
+ var calendar = createView(params);
+ calendar.destroy();
+
+ var initialInstanceNumber = instanceNumber;
+ instanceNumber = 0;
+
+ calendar = createView(params);
+
+ // call destroy function of controller to ensure that it correctly destroys everything
+ calendar.__destroy();
+
+ assert.strictEqual(instanceNumber, initialInstanceNumber+1, "every widget must be destroyed exept the parent");
+
+ calendar.destroy();
+
+ mixins.ParentedMixin.init = initWidget;
+ mixins.ParentedMixin.destroy = destroyWidget;
+ });
});
});
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index 672c7a7151d..9e440deda85 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -6,6 +6,7 @@ var config = require('web.config');
var core = require('web.core');
var fieldRegistry = require('web.field_registry');
var FormView = require('web.FormView');
+var mixins = require('web.mixins');
var pyeval = require('web.pyeval');
var RainbowMan = require('web.rainbow_man');
var testUtils = require('web.test_utils');
@@ -6337,5 +6338,84 @@ QUnit.module('Views', {
form.destroy();
});
+ QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ assert.expect(1);
+
+ var instanceNumber = 0;
+ var initWidget = mixins.ParentedMixin.init;
+ mixins.ParentedMixin.init = function () {
+ instanceNumber++;
+ return initWidget.apply(this, arguments);
+ };
+ var destroyWidget = mixins.ParentedMixin.destroy;
+ mixins.ParentedMixin.destroy = function () {
+ if (!this.isDestroyed()) {
+ instanceNumber--;
+ }
+ return destroyWidget.apply(this, arguments);
+ };
+
+ var params = {
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '
',
+ archs: {
+ 'partner,false,form':
+ '',
+ "partner_type,false,list": '',
+ 'product,false,list': '',
+
+ },
+ res_id: 1,
+ };
+
+ var form = createView(params);
+ form.destroy();
+
+ var initialInstanceNumber = instanceNumber;
+ instanceNumber = 0;
+
+ form = createView(params);
+
+ // call destroy function of controller to ensure that it correctly destroys everything
+ form.__destroy();
+
+ assert.strictEqual(instanceNumber, initialInstanceNumber+1, "every widget must be destroyed exept the parent");
+
+ form.destroy();
+
+ mixins.ParentedMixin.init = initWidget;
+ mixins.ParentedMixin.destroy = destroyWidget;
+ });
+
});
});
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index 250bb8ef64f..ed697c32712 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -5,6 +5,7 @@ var core = require('web.core');
var KanbanColumnProgressBar = require('web.KanbanColumnProgressBar');
var KanbanRenderer = require('web.KanbanRenderer');
var KanbanView = require('web.KanbanView');
+var mixins = require('web.mixins');
var testUtils = require('web.test_utils');
var Widget = require('web.Widget');
var widgetRegistry = require('web.widget_registry');
@@ -2484,6 +2485,63 @@ QUnit.module('Views', {
kanban.destroy();
});
+
+ QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ assert.expect(1);
+
+ var instanceNumber = 0;
+ var initWidget = mixins.ParentedMixin.init;
+ mixins.ParentedMixin.init = function () {
+ instanceNumber++;
+ return initWidget.apply(this, arguments);
+ };
+ var destroyWidget = mixins.ParentedMixin.destroy;
+ mixins.ParentedMixin.destroy = function () {
+ if (!this.isDestroyed()) {
+ instanceNumber--;
+ }
+ return destroyWidget.apply(this, arguments);
+ };
+
+ var params = {
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '
' +
+ '' +
+ '',
+ };
+
+ var kanban = createView(params);
+ kanban.destroy();
+
+ var initialInstanceNumber = instanceNumber;
+ instanceNumber = 0;
+
+ kanban = createView(params);
+
+ // call destroy function of controller to ensure that it correctly destroys everything
+ kanban.__destroy();
+
+ assert.strictEqual(instanceNumber, initialInstanceNumber+1, "every widget must be destroyed exept the parent");
+
+ kanban.destroy();
+
+ mixins.ParentedMixin.init = initWidget;
+ mixins.ParentedMixin.destroy = destroyWidget;
+ });
+
});
});
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index b03e3ff534d..6657c711b95 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -5,6 +5,7 @@ var config = require('web.config');
var basicFields = require('web.basic_fields');
var FormView = require('web.FormView');
var ListView = require('web.ListView');
+var mixins = require('web.mixins');
var testUtils = require('web.test_utils');
var widgetRegistry = require('web.widget_registry');
var Widget = require('web.Widget');
@@ -3246,6 +3247,62 @@ QUnit.module('Views', {
list.destroy();
});
+ QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ assert.expect(1);
+
+ var instanceNumber = 0;
+ var initWidget = mixins.ParentedMixin.init;
+ mixins.ParentedMixin.init = function () {
+ instanceNumber++;
+ return initWidget.apply(this, arguments);
+ };
+ var destroyWidget = mixins.ParentedMixin.destroy;
+ mixins.ParentedMixin.destroy = function () {
+ if (!this.isDestroyed()) {
+ instanceNumber--;
+ }
+ return destroyWidget.apply(this, arguments);
+ };
+
+ var params = {
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '' +
+ '',
+ };
+
+ var list = createView(params);
+ list.destroy();
+
+ var initialInstanceNumber = instanceNumber;
+ instanceNumber = 0;
+
+ list = createView(params);
+
+ // call destroy function of controller to ensure that it correctly destroys everything
+ list.__destroy();
+
+ assert.strictEqual(instanceNumber, initialInstanceNumber+1, "every widget must be destroyed exept the parent");
+
+ list.destroy();
+
+ mixins.ParentedMixin.init = initWidget;
+ mixins.ParentedMixin.destroy = destroyWidget;
+ });
+
});
});