summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorMichael Mattiello (mcm) <mcm@odoo.com>2020-10-19 10:58:34 +0000
committerMichael Mattiello (mcm) <mcm@odoo.com>2020-10-22 10:39:49 +0000
commit1ac67480ba995efbb2fb6f15d261c14c6828de76 (patch)
tree98f279588ddf4ec976a961804374a65db812accf /addons
parentb765ecf908b998773c9c2167f663580792069758 (diff)
[FIX] web: keep new widget el in ComponentAdapter
Before this commit, when sub widget replaced its el, the ComponentAdapter parent kept the previous el. This caused some issues as in the ActivityRecordAdapter which lost its event listeners when re-rendered. This commit forces the ComponentAdapter to keep the new sub widget el after being patched. task id: 2360021 closes odoo/odoo#60517 X-original-commit: 393b5fd4cfba254ad054a526996e82922f9057e2 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com> Signed-off-by: Michaƫl Mattiello <mcm-odoo@users.noreply.github.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/web/static/src/js/owl_compatibility.js6
-rw-r--r--addons/web/static/tests/owl_compatibility_tests.js144
2 files changed, 149 insertions, 1 deletions
diff --git a/addons/web/static/src/js/owl_compatibility.js b/addons/web/static/src/js/owl_compatibility.js
index b5ff2a026d1..a33f5ebed58 100644
--- a/addons/web/static/src/js/owl_compatibility.js
+++ b/addons/web/static/src/js/owl_compatibility.js
@@ -142,7 +142,11 @@ odoo.define('web.OwlCompatibility', function () {
}
vnode.elm = this.widget.el;
}
- return super.__patch(...arguments);
+ const result = super.__patch(...arguments);
+ if (this.widget && this.el !== this.widget.el) {
+ this.__owl__.vnode.elm = this.widget.el;
+ }
+ return result;
}
/**
diff --git a/addons/web/static/tests/owl_compatibility_tests.js b/addons/web/static/tests/owl_compatibility_tests.js
index 1cc463d0eeb..a4f453867cf 100644
--- a/addons/web/static/tests/owl_compatibility_tests.js
+++ b/addons/web/static/tests/owl_compatibility_tests.js
@@ -680,6 +680,150 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
parent.destroy();
});
+ QUnit.test("adapter keeps same el as sub widget (modify)", async function (assert) {
+ assert.expect(7);
+
+ let myWidget;
+ const MyWidget = Widget.extend({
+ events: {
+ click: "_onClick",
+ },
+ init: function (parent, name) {
+ myWidget = this;
+ this._super.apply(this, arguments);
+ this.name = name;
+ },
+ start: function () {
+ this.render();
+ },
+ render: function () {
+ this.$el.text("Click me!");
+ },
+ update: function (name) {
+ this.name = name;
+ },
+ _onClick: function () {
+ assert.step(this.name);
+ },
+ });
+ class MyWidgetAdapter extends ComponentAdapter {
+ updateWidget(nextProps) {
+ return this.widget.update(nextProps.name);
+ }
+ renderWidget() {
+ this.widget.render();
+ }
+ }
+ class Parent extends Component {
+ constructor() {
+ super(...arguments);
+ this.MyWidget = MyWidget;
+ this.state = useState({
+ name: "GED",
+ });
+ }
+ }
+ Parent.template = xml`
+ <MyWidgetAdapter Component="MyWidget" name="state.name"/>
+ `;
+ Parent.components = { MyWidgetAdapter };
+
+ const target = testUtils.prepareTarget();
+ const parent = new Parent();
+ await parent.mount(target);
+
+ assert.strictEqual(parent.el, myWidget.el);
+ await testUtils.dom.click(parent.el);
+
+ parent.state.name = "AAB";
+ await nextTick();
+
+ assert.strictEqual(parent.el, myWidget.el);
+ await testUtils.dom.click(parent.el);
+
+ parent.state.name = "MCM";
+ await nextTick();
+
+ assert.strictEqual(parent.el, myWidget.el);
+ await testUtils.dom.click(parent.el);
+
+ assert.verifySteps(["GED", "AAB", "MCM"]);
+
+ parent.destroy();
+ });
+
+ QUnit.test("adapter keeps same el as sub widget (replace)", async function (assert) {
+ assert.expect(7);
+
+ let myWidget;
+ const MyWidget = Widget.extend({
+ events: {
+ click: "_onClick",
+ },
+ init: function (parent, name) {
+ myWidget = this;
+ this._super.apply(this, arguments);
+ this.name = name;
+ },
+ start: function () {
+ this.render();
+ },
+ render: function () {
+ this._replaceElement("<div>Click me!</div>");
+ },
+ update: function (name) {
+ this.name = name;
+ },
+ _onClick: function () {
+ assert.step(this.name);
+ },
+ });
+ class MyWidgetAdapter extends ComponentAdapter {
+ updateWidget(nextProps) {
+ return this.widget.update(nextProps.name);
+ }
+ renderWidget() {
+ this.widget.render();
+ }
+ }
+ class Parent extends Component {
+ constructor() {
+ super(...arguments);
+ this.MyWidget = MyWidget;
+ this.state = useState({
+ name: "GED",
+ });
+ }
+ }
+ Parent.template = xml`
+ <MyWidgetAdapter Component="MyWidget" name="state.name"/>
+ `;
+ Parent.components = { MyWidgetAdapter };
+
+ const target = testUtils.prepareTarget();
+ const parent = new Parent();
+ await parent.mount(target);
+
+ assert.strictEqual(parent.el, myWidget.el);
+ await testUtils.dom.click(parent.el);
+
+ parent.state.name = "AAB";
+ await nextTick();
+
+ assert.strictEqual(parent.el, myWidget.el);
+ await testUtils.dom.click(parent.el);
+
+ parent.state.name = "MCM";
+ await nextTick();
+
+ assert.strictEqual(parent.el, myWidget.el);
+ await testUtils.dom.click(parent.el);
+
+ assert.verifySteps(["GED", "AAB", "MCM"]);
+
+ parent.destroy();
+ });
+
QUnit.module('WidgetAdapterMixin and ComponentWrapper');
QUnit.test("widget with sub component", async function (assert) {