diff --git a/src/qweb/qweb.ts b/src/qweb/qweb.ts
index 2de45442..0e006c5d 100644
--- a/src/qweb/qweb.ts
+++ b/src/qweb/qweb.ts
@@ -137,12 +137,26 @@ const UTILS: Utils = {
}
return result;
},
+ /**
+ * This method combines the current context with the variables defined in a
+ * scope for use in a slot.
+ *
+ * The implementation is kind of tricky because we want to preserve the
+ * prototype chain structure of the cloned result. So we need to traverse the
+ * prototype chain, cloning each level respectively.
+ */
combine(context, scope) {
- const clone = Object.create(context);
+ let clone = context;
+ const scopeStack = [];
while (!isComponent(scope)) {
- Object.assign(clone, scope);
+ scopeStack.push(scope);
scope = scope.__proto__;
}
+ while (scopeStack.length) {
+ let scope = scopeStack.pop();
+ clone = Object.create(clone);
+ Object.assign(clone, scope);
+ }
return clone;
},
shallowEqual,
diff --git a/tests/component/slots.test.ts b/tests/component/slots.test.ts
index 54297cdc..ca9f88e4 100644
--- a/tests/component/slots.test.ts
+++ b/tests/component/slots.test.ts
@@ -1303,4 +1303,71 @@ describe("t-slot directive", () => {
document.querySelector("button").click();
await nextTick();
});
+
+ test("t-slot in recursive templates", async () => {
+ QWeb.registerTemplate(
+ "_test_recursive_template",
+ `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+ );
+
+ class Wrapper extends Component {
+ static template = xml`
+
+
+ `;
+ }
+
+ class Parent extends Component {
+ static template = "_test_recursive_template";
+ static components = { Wrapper };
+ name = "foo";
+ items = [
+ {
+ name: "foo-0",
+ children: [
+ { name: "foo-00", children: [] },
+ {
+ name: "foo-01",
+ children: [
+ { name: "foo-010", children: [] },
+ { name: "foo-011", children: [] },
+ {
+ name: "foo-012",
+ children: [
+ { name: "foo-0120", children: [] },
+ { name: "foo-0121", children: [] },
+ { name: "foo-0122", children: [] },
+ ],
+ },
+ ],
+ },
+ { name: "foo-02", children: [] },
+ ],
+ },
+ { name: "foo-1", children: [] },
+ { name: "foo-2", children: [] },
+ ];
+ }
+
+ await mount(Parent, { target: fixture });
+
+ expect(fixture.innerHTML).toBe(
+ "foofoo-0foo-00foo-01foo-010foo-011foo-012foo-0120foo-0121foo-0122foo-02foo-1foo-2"
+ );
+ });
});