[FIX] refs in recursive templates now work properly

This commit is contained in:
Géry Debongnie
2022-02-09 09:28:24 +01:00
committed by Samuel Degueldre
parent 74faa8bb82
commit a9f29c4caa
4 changed files with 65 additions and 8 deletions
+7 -6
View File
@@ -299,7 +299,7 @@ interface BlockCtx {
locations: IndexedLocation[]; locations: IndexedLocation[];
children: Child[]; children: Child[];
cbRefs: number[]; cbRefs: number[];
refList: (() => void)[]; refList: (() => void)[][];
} }
function buildContext(tree: IntermediateTree, ctx?: BlockCtx, fromIdx?: number): BlockCtx { function buildContext(tree: IntermediateTree, ctx?: BlockCtx, fromIdx?: number): BlockCtx {
@@ -409,8 +409,7 @@ function updateCtx(ctx: BlockCtx, tree: IntermediateTree) {
break; break;
} }
case "ref": case "ref":
const index = ctx.refList.push(NO_OP) - 1; const index = ctx.cbRefs.push(info.idx) - 1;
ctx.cbRefs.push(info.idx);
ctx.locations.push({ ctx.locations.push({
idx: info.idx, idx: info.idx,
refIdx: info.refIdx!, refIdx: info.refIdx!,
@@ -430,10 +429,12 @@ function buildBlock(template: HTMLElement, ctx: BlockCtx): BlockType {
if (ctx.cbRefs.length) { if (ctx.cbRefs.length) {
const cbRefs = ctx.cbRefs; const cbRefs = ctx.cbRefs;
const refList = ctx.refList; const refList = ctx.refList;
let cbRefsNumber = cbRefs.length;
B = class extends B { B = class extends B {
mount(parent: HTMLElement, afterNode: Node | null) { mount(parent: HTMLElement, afterNode: Node | null) {
refList.push(new Array(cbRefsNumber));
super.mount(parent, afterNode); super.mount(parent, afterNode);
for (let cbRef of refList) { for (let cbRef of refList.pop()!) {
cbRef(); cbRef();
} }
} }
@@ -620,8 +621,8 @@ function setText(this: Text, value: any) {
characterDataSetData.call(this, toText(value)); characterDataSetData.call(this, toText(value));
} }
function makeRefSetter(index: number, refs: (() => void)[]): Setter<HTMLElement> { function makeRefSetter(index: number, refs: (() => void)[][]): Setter<HTMLElement> {
return function setRef(this: HTMLElement, fn: any) { return function setRef(this: HTMLElement, fn: any) {
refs[index] = () => fn(this); refs[refs.length - 1][index] = () => fn(this);
}; };
} }
+13
View File
@@ -1,4 +1,5 @@
import { createBlock, mount, patch, remove } from "../../src/blockdom"; import { createBlock, mount, patch, remove } from "../../src/blockdom";
import { logStep } from "../helpers";
import { makeTestFixture } from "./helpers"; import { makeTestFixture } from "./helpers";
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -55,3 +56,15 @@ test("is in dom when callback is called", async () => {
mount(tree, fixture); mount(tree, fixture);
}); });
test("callback ref in callback ref with same block", async () => {
const block = createBlock('<p block-ref="0"><block-text-1/><block-child-0/></p>');
let refFn = (el: HTMLParagraphElement) => logStep(el.outerHTML);
const child = block([refFn, "child"], []);
const parent = block([refFn, "parent"], [child]);
mount(parent, fixture);
expect(fixture.innerHTML).toBe("<p>parent<p>child</p></p>");
expect(["<p>child</p>", "<p>parent<p>child</p></p>"]).toBeLogged();
});
@@ -38,6 +38,26 @@ exports[`refs can use 2 refs with same name in a t-if/t-else situation 1`] = `
}" }"
`; `;
exports[`refs refs and recursive templates 1`] = `
"function anonymous(bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, component, comment } = bdom;
let block1 = createBlock(\`<p block-ref=\\"0\\"><block-text-1/><block-child-0/></p>\`);
return function template(ctx, node, key = \\"\\") {
const refs = ctx.__owl__.refs;
const ref1 = (el) => refs[\`root\`] = el;
let b2;
let txt1 = ctx['props'].tree.value;
if (ctx['props'].tree.child) {
b2 = component(\`Test\`, {tree: ctx['props'].tree.child}, key + \`__1\`, node, ctx);
}
return block1([ref1, txt1], [b2]);
}
}"
`;
exports[`refs refs are properly bound in slots 1`] = ` exports[`refs refs are properly bound in slots 1`] = `
"function anonymous(bdom, helpers "function anonymous(bdom, helpers
) { ) {
+25 -2
View File
@@ -1,5 +1,5 @@
import { Component, mount, useRef, useState } from "../../src/index"; import { Component, mount, onMounted, useRef, useState } from "../../src/index";
import { makeTestFixture, nextTick, snapshotEverything } from "../helpers"; import { logStep, makeTestFixture, nextTick, snapshotEverything } from "../helpers";
import { xml } from "../../src/index"; import { xml } from "../../src/index";
snapshotEverything(); snapshotEverything();
@@ -100,4 +100,27 @@ describe("refs", () => {
expect(console.warn).toBeCalledTimes(1); expect(console.warn).toBeCalledTimes(1);
console.warn = consoleWarn; console.warn = consoleWarn;
}); });
test("refs and recursive templates", async () => {
class Test extends Component {
static components = {};
static template = xml`
<p t-ref="root">
<t t-esc="props.tree.value"/>
<t t-if="props.tree.child"><Test tree="props.tree.child"/></t>
</p>`;
root = useRef("root");
setup() {
onMounted(() => logStep(this.root.el!.outerHTML));
}
}
Test.components = { Test };
const tree = { value: "a", child: { value: "b", child: null } };
await mount(Test, fixture, { props: { tree } });
expect(fixture.innerHTML).toBe("<p>a<p>b</p></p>");
expect(["<p>b</p>", "<p>a<p>b</p></p>"]).toBeLogged();
});
}); });