[IMP] portal: ensure that destroy is synchronous

This commit is contained in:
Géry Debongnie
2022-01-19 13:53:07 +01:00
committed by Samuel Degueldre
parent 7b3593ff8f
commit dfc090bb12
3 changed files with 74 additions and 7 deletions
+8 -7
View File
@@ -35,9 +35,11 @@ class VPortal extends VText implements Partial<VNode<VPortal>> {
this.realBDom!.beforeRemove(); this.realBDom!.beforeRemove();
} }
remove() { remove() {
super.remove(); if (this.realBDom) {
this.realBDom!.remove(); super.remove();
this.realBDom = null; this.realBDom!.remove();
this.realBDom = null;
}
} }
patch(other: VPortal) { patch(other: VPortal) {
@@ -64,10 +66,9 @@ export class Portal extends Component {
const node = this.__owl__; const node = this.__owl__;
const renderFn = node.renderFn; const renderFn = node.renderFn;
node.renderFn = () => new VPortal(this.props.target, renderFn()); node.renderFn = () => new VPortal(this.props.target, renderFn());
onWillUnmount(async () => { onWillUnmount(() => {
await Promise.resolve(); if (node.bdom) {
if (node.bdom && (node.bdom as any).realBDom) { node.bdom.remove();
(node.bdom as any).realBDom.remove();
} }
}); });
} }
@@ -83,6 +83,36 @@ exports[`Portal Add and remove portals with t-foreach 1`] = `
}" }"
`; `;
exports[`Portal Add and remove portals with t-foreach and destroy 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let { prepareList, Portal, capture, withKey } = helpers;
let block2 = createBlock(\`<div><block-text-0/><block-child-0/></div>\`);
function slot1(ctx, node, key = \\"\\") {
let b4 = text(\` Portal\`);
let b5 = text(ctx['portalId']);
return multi([b4, b5]);
}
return function template(ctx, node, key = \\"\\") {
ctx = Object.create(ctx);
const [k_block1, v_block1, l_block1, c_block1] = prepareList(ctx['portalIds']);
for (let i1 = 0; i1 < l_block1; i1++) {
ctx[\`portalId\`] = v_block1[i1];
let key1 = ctx['portalId'];
let txt1 = ctx['portalId'];
const ctx1 = capture(ctx);
let b6 = component(Portal, {target: '#outside',slots: {'default': {__render: slot1, __ctx: ctx1}}}, key + \`__1__\${key1}\`, node, ctx);
c_block1[i1] = withKey(block2([txt1], [b6]), key1);
}
return list(c_block1);
}
}"
`;
exports[`Portal Add and remove portals with t-foreach inside div 1`] = ` exports[`Portal Add and remove portals with t-foreach inside div 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
+36
View File
@@ -1,4 +1,5 @@
import { import {
App,
Component, Component,
mount, mount,
onError, onError,
@@ -653,6 +654,41 @@ describe("Portal", () => {
expect(fixture.innerHTML).toBe('<div id="outside"></div>'); expect(fixture.innerHTML).toBe('<div id="outside"></div>');
}); });
test("Add and remove portals with t-foreach and destroy", async () => {
class Parent extends Component {
static template = xml`
<t t-foreach="portalIds" t-as="portalId" t-key="portalId">
<div>
<t t-esc="portalId"/>
<t t-portal="'#outside'">
Portal<t t-esc="portalId"/>
</t>
</div>
</t>`;
portalIds = useState([] as any);
}
addOutsideDiv(fixture);
const app = new App(Parent);
const parent = await app.mount(fixture);
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
parent.portalIds.push(1);
await nextTick();
expect(fixture.innerHTML).toBe('<div id="outside"> Portal1</div><div>1</div>');
parent.portalIds.push(2);
await nextTick();
expect(fixture.innerHTML).toBe(
'<div id="outside"> Portal1 Portal2</div><div>1</div><div>2</div>'
);
app.destroy();
//This will test explicitly that we don't use an await nextTick(); after the destroy.
expect(fixture.innerHTML).toBe('<div id="outside"></div>');
});
test("conditional use of Portal with div", async () => { test("conditional use of Portal with div", async () => {
class Parent extends Component { class Parent extends Component {
static template = xml` static template = xml`