Owl is a template based component system. There is therefore a need to be able
to make generic components. For example, imagine a generic Dialog
component, which is able to display some arbitrary content.
Obviously, we want to use this component everywhere in our application, to
display various different content. The Dialog
component is technically the
owner of its content, but is only a container. The user of the Dialog
is
the component that want to inject something inside the Dialog
. This is
exactly what slots are for.
To make generic components, it is useful to be able for a parent component to inject some sub template, but still be the owner. For example, a generic dialog component will need to render some content, some footer, but with the parent as the rendering context.
Slots are inserted with the t-slot
directive:
<div t-name="Dialog" class="modal">
<div class="modal-title"><t t-esc="props.title"/></div>
<div class="modal-content">
<t t-slot="content"/>
</div>
<div class="modal-footer">
<t t-slot="footer"/>
</div>
</div>
Slots are defined by the caller, with the t-set-slot
directive:
<div t-name="SomeComponent">
<div>some component</div>
<Dialog title="'Some Dialog'">
<t t-set-slot="content">
<div>hey</div>
</t>
<t t-set-slot="footer">
<button t-on-click="doSomething">ok</button>
</t>
</Dialog>
</div>
In this example, the component Dialog
will render the slots content
and footer
with its parent as rendering context. This means that clicking on the button
will execute the doSomething
method on the parent, not on the dialog.
Note: Owl previously used the t-set
directive to define the content of a slot.
This is deprecated and should no longer be used in new code.
The first element inside the component which is not a named slot will
be considered the default
slot. For example:
<div t-name="Parent">
<Child>
<span>some content</span>
</Child>
</div>
<div t-name="Child">
<t t-slot="default"/>
</div>
Slots can define a default content, in case the parent did not define them:
<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> -->
Rendering context: the content of the slots is actually rendered with the rendering context corresponding to where it was defined, not where it is positioned. This allows the user to define event handlers that will be bound to the correct component (usually, the grandparent of the slot content).
The t-slot
directive is actually able to use any expressions, using string
interplolation:
<t t-slot="{{current}}" />