mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
@@ -865,6 +865,19 @@ be considered the `default` slot. For example:
|
|||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Slots can define a default content, in case the parent did not define them:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div t-name="Parent">
|
||||||
|
<Child/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span t-name="Child">
|
||||||
|
<t t-slot="default">default content</t>
|
||||||
|
</span>
|
||||||
|
<!-- will be rendered as: <div><span>default content</span></div> -->
|
||||||
|
```
|
||||||
|
|
||||||
### Dynamic sub components
|
### Dynamic sub components
|
||||||
|
|
||||||
It is not common, but sometimes we need a dynamic component name. In this case,
|
It is not common, but sometimes we need a dynamic component name. In this case,
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ QWeb.addDirective({
|
|||||||
QWeb.addDirective({
|
QWeb.addDirective({
|
||||||
name: "slot",
|
name: "slot",
|
||||||
priority: 80,
|
priority: 80,
|
||||||
atNodeEncounter({ ctx, value }): boolean {
|
atNodeEncounter({ ctx, value, node, qweb }): boolean {
|
||||||
const slotKey = ctx.generateID();
|
const slotKey = ctx.generateID();
|
||||||
ctx.addLine(
|
ctx.addLine(
|
||||||
`const slot${slotKey} = this.constructor.slots[context.__owl__.slotId + '_' + '${value}'];`
|
`const slot${slotKey} = this.constructor.slots[context.__owl__.slotId + '_' + '${value}'];`
|
||||||
@@ -214,6 +214,12 @@ QWeb.addDirective({
|
|||||||
if (!ctx.parentNode) {
|
if (!ctx.parentNode) {
|
||||||
ctx.addLine(`utils.defineProxy(result, ${parentNode}[0]);`);
|
ctx.addLine(`utils.defineProxy(result, ${parentNode}[0]);`);
|
||||||
}
|
}
|
||||||
|
if (node.hasChildNodes()) {
|
||||||
|
ctx.addElse();
|
||||||
|
const nodeCopy = <Element>node.cloneNode(true);
|
||||||
|
nodeCopy.removeAttribute("t-slot");
|
||||||
|
qweb._compileNode(nodeCopy, ctx);
|
||||||
|
}
|
||||||
ctx.closeIf();
|
ctx.closeIf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1395,6 +1395,23 @@ exports[`t-slot directive content is the default slot 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`t-slot directive dafault slots can define a default content 1`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"__template__1\\"
|
||||||
|
var h = this.h;
|
||||||
|
let c5 = [], p5 = {key:5};
|
||||||
|
var vn5 = h('span', p5, c5);
|
||||||
|
const slot6 = this.constructor.slots[context.__owl__.slotId + '_' + 'default'];
|
||||||
|
if (slot6) {
|
||||||
|
slot6.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c5, parent: extra.parent || context}));
|
||||||
|
} else {
|
||||||
|
c5.push({text: \`default content\`});
|
||||||
|
}
|
||||||
|
return vn5;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`t-slot directive default slot work with text nodes 1`] = `
|
exports[`t-slot directive default slot work with text nodes 1`] = `
|
||||||
"function anonymous(context, extra
|
"function anonymous(context, extra
|
||||||
) {
|
) {
|
||||||
@@ -1439,6 +1456,23 @@ exports[`t-slot directive multiple roots are allowed in a named slot 1`] = `
|
|||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`t-slot directive named slots can define a default content 1`] = `
|
||||||
|
"function anonymous(context, extra
|
||||||
|
) {
|
||||||
|
// Template name: \\"__template__1\\"
|
||||||
|
var h = this.h;
|
||||||
|
let c5 = [], p5 = {key:5};
|
||||||
|
var vn5 = h('span', p5, c5);
|
||||||
|
const slot6 = this.constructor.slots[context.__owl__.slotId + '_' + 'header'];
|
||||||
|
if (slot6) {
|
||||||
|
slot6.call(this, context.__owl__.scope, Object.assign({}, extra, {parentNode: c5, parent: extra.parent || context}));
|
||||||
|
} else {
|
||||||
|
c5.push({text: \`default content\`});
|
||||||
|
}
|
||||||
|
return vn5;
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`t-slot directive refs are properly bound in slots 1`] = `
|
exports[`t-slot directive refs are properly bound in slots 1`] = `
|
||||||
"function anonymous(context, extra
|
"function anonymous(context, extra
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -4032,6 +4032,76 @@ describe("t-slot directive", () => {
|
|||||||
expect(QWeb.slots["1_footer"].toString()).toMatchSnapshot();
|
expect(QWeb.slots["1_footer"].toString()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("named slots can define a default content", async () => {
|
||||||
|
class Dialog extends Component<any, any> {
|
||||||
|
static template = xml`
|
||||||
|
<span>
|
||||||
|
<t t-slot="header">default content</t>
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
class Parent extends Component<any, any> {
|
||||||
|
static template = xml`<div><Dialog/></div>`;
|
||||||
|
static components = { Dialog };
|
||||||
|
}
|
||||||
|
const parent = new Parent();
|
||||||
|
await parent.mount(fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("<div><span>default content</span></div>");
|
||||||
|
expect(env.qweb.templates[Dialog.template].fn.toString()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("dafault slots can define a default content", async () => {
|
||||||
|
class Dialog extends Component<any, any> {
|
||||||
|
static template = xml`
|
||||||
|
<span>
|
||||||
|
<t t-slot="default">default content</t>
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
class Parent extends Component<any, any> {
|
||||||
|
static template = xml`<div><Dialog/></div>`;
|
||||||
|
static components = { Dialog };
|
||||||
|
}
|
||||||
|
const parent = new Parent();
|
||||||
|
await parent.mount(fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("<div><span>default content</span></div>");
|
||||||
|
expect(env.qweb.templates[Dialog.template].fn.toString()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("default content is not rendered if slot is provided", async () => {
|
||||||
|
class Dialog extends Component<any, any> {
|
||||||
|
static template = xml`
|
||||||
|
<span>
|
||||||
|
<t t-slot="default">default content</t>
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
class Parent extends Component<any, any> {
|
||||||
|
static template = xml`<div><Dialog>hey</Dialog></div>`;
|
||||||
|
static components = { Dialog };
|
||||||
|
}
|
||||||
|
const parent = new Parent();
|
||||||
|
await parent.mount(fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("<div><span>hey</span></div>");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("default content is not rendered if named slot is provided", async () => {
|
||||||
|
class Dialog extends Component<any, any> {
|
||||||
|
static template = xml`
|
||||||
|
<span>
|
||||||
|
<t t-slot="header">default content</t>
|
||||||
|
</span>`;
|
||||||
|
}
|
||||||
|
class Parent extends Component<any, any> {
|
||||||
|
static template = xml`<div><Dialog><t t-set="header">hey</t></Dialog></div>`;
|
||||||
|
static components = { Dialog };
|
||||||
|
}
|
||||||
|
const parent = new Parent();
|
||||||
|
await parent.mount(fixture);
|
||||||
|
|
||||||
|
expect(fixture.innerHTML).toBe("<div><span>hey</span></div>");
|
||||||
|
});
|
||||||
|
|
||||||
test("slots are rendered with proper context", async () => {
|
test("slots are rendered with proper context", async () => {
|
||||||
env.qweb.addTemplates(`
|
env.qweb.addTemplates(`
|
||||||
<templates>
|
<templates>
|
||||||
|
|||||||
Reference in New Issue
Block a user