Skip to content

Commit

Permalink
[FIX] compiler: compile named slot in t-component in named slot
Browse files Browse the repository at this point in the history
Previously, if a t-set-slot was inside a t-component itself inside a
t-set-slot the parser would crash, because the slot is removed from the
template before compiling its content, causing a further check's
assumption to be broken (the t-set-slot remains connected to the
component's xml node)
  • Loading branch information
sdegueldre authored and ged-odoo committed Nov 15, 2023
1 parent b7c37ca commit a53e425
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -740,14 +740,14 @@ function parseComponent(node: Element, ctx: ParsingContext): AST | null {
// be ignored)
let el = slotNode.parentElement!;
let isInSubComponent = false;
while (el !== clone) {
while (el && el !== clone) {
if (el!.hasAttribute("t-component") || el!.tagName[0] === el!.tagName[0].toUpperCase()) {
isInSubComponent = true;
break;
}
el = el.parentElement!;
}
if (isInSubComponent) {
if (isInSubComponent || !el) {
continue;
}

Expand Down
39 changes: 39 additions & 0 deletions tests/components/__snapshots__/slots.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,45 @@ exports[`slots multiple slots containing components 3`] = `
}"
`;

exports[`slots named slot inside named slot in t-component 1`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { capture, markRaw } = helpers;
const comp1 = app.createComponent(null, false, true, false, []);
const comp2 = app.createComponent(\`Child\`, true, true, false, []);

function slot1(ctx, node, key = \\"\\") {
const b2 = text(\` outer \`);
const ctx2 = capture(ctx);
const Comp1 = ctx['Child'];
const b4 = toggler(Comp1, comp1({slots: markRaw({'brol': {__render: slot2.bind(this), __ctx: ctx2}})}, (Comp1).name + key + \`__1\`, node, this, Comp1));
return multi([b2, b4]);
}

function slot2(ctx, node, key = \\"\\") {
return text(ctx['value']);
}

return function template(ctx, node, key = \\"\\") {
const ctx1 = capture(ctx);
return comp2({slots: markRaw({'brol': {__render: slot1.bind(this), __ctx: ctx1}})}, key + \`__2\`, node, this, null);
}
}"
`;

exports[`slots named slot inside named slot in t-component 2`] = `
"function anonymous(app, bdom, helpers
) {
let { text, createBlock, list, multi, html, toggler, comment } = bdom;
let { callSlot } = helpers;

return function template(ctx, node, key = \\"\\") {
return callSlot(ctx, node, key, 'brol', false, {});
}
}"
`;

exports[`slots named slot inside slot 1`] = `
"function anonymous(app, bdom, helpers
) {
Expand Down
25 changes: 25 additions & 0 deletions tests/components/slots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1673,6 +1673,31 @@ describe("slots", () => {
expect(fixture.innerHTML).toBe("<div><div><p>Ablip</p><div><p>Bblip</p></div></div></div>");
});

test("named slot inside named slot in t-component", async () => {
class Child extends Component {
static template = xml`<t t-slot="brol"/>`;
}
class Parent extends Component {
static template = xml`
<Child>
<t t-set-slot="brol">
outer
<t t-component="Child">
<t t-set-slot="brol">
<t t-esc="value"/>
</t>
</t>
</t>
</Child>`;
static components = { Child };
Child = Child;
value = "inner";
}
await mount(Parent, fixture);

expect(fixture.innerHTML).toBe(" outer inner");
});

test("can render only empty slot", async () => {
class Parent extends Component {
static template = xml`<t t-slot="default"/>`;
Expand Down

0 comments on commit a53e425

Please sign in to comment.