mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[FIX] component: t-refs are bound/unbound at proper timing
With this commit, we make sure that bound references are removed when a widget is removed from the DOM. closes #59
This commit is contained in:
committed by
Géry Debongnie
parent
4c2115d365
commit
379cd2a90f
+13
-9
@@ -1072,27 +1072,31 @@ const widgetDirective: Directive = {
|
|||||||
ctx.addLine(`w${widgetID}.on('${event}', owner, owner['${method}'])`);
|
ctx.addLine(`w${widgetID}.on('${event}', owner, owner['${method}'])`);
|
||||||
}
|
}
|
||||||
let ref = node.getAttribute("t-ref");
|
let ref = node.getAttribute("t-ref");
|
||||||
let refExpr = ref ? `context.refs[${ctx.formatExpression(ref)}] = w${widgetID};` : '';
|
let refExpr = ref
|
||||||
|
? `context.refs[${ctx.formatExpression(ref)}] = w${widgetID};`
|
||||||
|
: "";
|
||||||
|
|
||||||
ctx.addLine(`def${defID} = w${widgetID}._prepare();`);
|
ctx.addLine(`def${defID} = w${widgetID}._prepare();`);
|
||||||
ctx.closeIf();
|
ctx.closeIf();
|
||||||
ctx.closeIf();
|
ctx.closeIf();
|
||||||
|
|
||||||
|
let finalizeWidgetCode = `w${widgetID}.${
|
||||||
|
keepAlive ? "unmount" : "destroy"
|
||||||
|
}()`;
|
||||||
|
if (ref) {
|
||||||
|
finalizeWidgetCode += `;delete context.refs[${ctx.formatExpression(
|
||||||
|
ref
|
||||||
|
)}]`;
|
||||||
|
}
|
||||||
ctx.addIf(`isNew${widgetID}`);
|
ctx.addIf(`isNew${widgetID}`);
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`def${defID} = def${defID}.then(vnode=>{let pvnode=h(vnode.sel, {key: ${templateID}});c${
|
`def${defID} = def${defID}.then(vnode=>{let pvnode=h(vnode.sel, {key: ${templateID}});c${
|
||||||
ctx.parentNode
|
ctx.parentNode
|
||||||
}[_${dummyID}_index]=pvnode;pvnode.data.hook = {insert(vn){let nvn=w${widgetID}._mount(vnode, vn.elm);pvnode.elm=nvn.elm;${refExpr}},remove(){w${widgetID}.${
|
}[_${dummyID}_index]=pvnode;pvnode.data.hook = {insert(vn){let nvn=w${widgetID}._mount(vnode, vn.elm);pvnode.elm=nvn.elm;${refExpr}},remove(){${finalizeWidgetCode}},destroy(){${finalizeWidgetCode}}}; w${widgetID}.__owl__.pvnode = pvnode;});`
|
||||||
keepAlive ? "unmount" : "destroy"
|
|
||||||
}()},destroy(){w${widgetID}.${
|
|
||||||
keepAlive ? "unmount" : "destroy"
|
|
||||||
}()}}; w${widgetID}.__owl__.pvnode = pvnode;});`
|
|
||||||
);
|
);
|
||||||
ctx.addElse();
|
ctx.addElse();
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`def${defID} = def${defID}.then(()=>{if (w${widgetID}.__owl__.isDestroyed) {return};let vnode;if (!w${widgetID}.__owl__.vnode){vnode=w${widgetID}.__owl__.pvnode} else { vnode=h(w${widgetID}.__owl__.vnode.sel, {key: ${templateID}});vnode.elm=w${widgetID}.el;vnode.data.hook = {insert(a){a.elm.parentNode.replaceChild(w${widgetID}.el,a.elm);a.elm=w${widgetID}.el;w${widgetID}.__mount();},remove(){w${widgetID}.${
|
`def${defID} = def${defID}.then(()=>{if (w${widgetID}.__owl__.isDestroyed) {return};let vnode;if (!w${widgetID}.__owl__.vnode){vnode=w${widgetID}.__owl__.pvnode} else { vnode=h(w${widgetID}.__owl__.vnode.sel, {key: ${templateID}});vnode.elm=w${widgetID}.el;vnode.data.hook = {insert(a){a.elm.parentNode.replaceChild(w${widgetID}.el,a.elm);a.elm=w${widgetID}.el;w${widgetID}.__mount();},remove(){${finalizeWidgetCode}}, destroy() {${finalizeWidgetCode}}}}c${
|
||||||
keepAlive ? "unmount" : "destroy"
|
|
||||||
}()}, destroy() {w${widgetID}.${keepAlive ? "unmount" : "destroy"}()}}}c${
|
|
||||||
ctx.parentNode
|
ctx.parentNode
|
||||||
}[_${dummyID}_index]=vnode;});`
|
}[_${dummyID}_index]=vnode;});`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -680,6 +680,52 @@ describe("composition", () => {
|
|||||||
await nextTick()
|
await nextTick()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("t-refs are bound at proper timing (2)", async () => {
|
||||||
|
expect.assertions(10);
|
||||||
|
class ParentWidget extends Widget {
|
||||||
|
inlineTemplate = `
|
||||||
|
<div>
|
||||||
|
<t t-if="state.child1" t-ref="'child1'" t-widget="Widget"/>
|
||||||
|
<t t-if="state.child2" t-ref="'child2'" t-widget="Widget"/>
|
||||||
|
</div>`;
|
||||||
|
widgets = { Widget };
|
||||||
|
state = { child1: true, child2: false };
|
||||||
|
count = 0;
|
||||||
|
mounted() {
|
||||||
|
expect(this.refs.child1).toBeDefined();
|
||||||
|
expect(this.refs.child2).toBeUndefined();
|
||||||
|
}
|
||||||
|
willPatch() {
|
||||||
|
if (this.count === 0) {
|
||||||
|
expect(this.refs.child1).toBeDefined();
|
||||||
|
expect(this.refs.child2).toBeUndefined();
|
||||||
|
}
|
||||||
|
if (this.count === 1) {
|
||||||
|
expect(this.refs.child1).toBeDefined();
|
||||||
|
expect(this.refs.child2).toBeDefined();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
patched() {
|
||||||
|
if (this.count === 0) {
|
||||||
|
expect(this.refs.child1).toBeDefined();
|
||||||
|
expect(this.refs.child2).toBeDefined();
|
||||||
|
}
|
||||||
|
if (this.count === 1) {
|
||||||
|
expect(this.refs.child1).toBeUndefined();
|
||||||
|
expect(this.refs.child2).toBeDefined();
|
||||||
|
}
|
||||||
|
this.count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = new ParentWidget(env);
|
||||||
|
await parent.mount(fixture);
|
||||||
|
parent.state.child2 = true;
|
||||||
|
await nextTick()
|
||||||
|
parent.state.child1 = false;
|
||||||
|
await nextTick()
|
||||||
|
});
|
||||||
|
|
||||||
test("modifying a sub widget", async () => {
|
test("modifying a sub widget", async () => {
|
||||||
class ParentWidget extends Widget {
|
class ParentWidget extends Widget {
|
||||||
inlineTemplate = `<div><t t-widget="Counter"/></div>`;
|
inlineTemplate = `<div><t t-widget="Counter"/></div>`;
|
||||||
|
|||||||
Reference in New Issue
Block a user