mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[DOC] add more information to the slots page
This commit is contained in:
committed by
Aaron Bohy
parent
cccb379377
commit
82f6923a21
+177
-50
@@ -3,68 +3,89 @@
|
|||||||
## Content
|
## Content
|
||||||
|
|
||||||
- [Overview](#overview)
|
- [Overview](#overview)
|
||||||
- [Example](#example)
|
- [Named slots](#named-slots)
|
||||||
- [Reference](#reference)
|
- [Rendering Context](#rendering-context)
|
||||||
|
- [Default Slot](#default-slot)
|
||||||
|
- [Default Content](#default-content)
|
||||||
|
- [Dynamic slots](#dynamic-slots)
|
||||||
|
- [Slots and props](#slots-and-props)
|
||||||
|
- [Slot params](#slot-params)
|
||||||
|
- [Slot scopes](#slot-scopes)
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Owl is a template based component system. There is therefore a need to be able
|
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`
|
to make generic components. For example, imagine a generic `Navbar`
|
||||||
component, which is able to display some arbitrary content.
|
component, which displays a navbar, but with some customizable content. Since
|
||||||
|
the specific content is only known to the user of the `Navbar`, it would be nice
|
||||||
Obviously, we want to use this component everywhere in our application, to
|
to specify it in the template where `Navbar` is used:
|
||||||
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.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<div t-name="Dialog" class="modal">
|
<div>
|
||||||
<div class="modal-title"><t t-esc="props.title"/></div>
|
<Navbar>
|
||||||
<div class="modal-content">
|
<span>Hello Owl</span>
|
||||||
|
</Navbar>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
This is exactly the way slots work! In the example above, the user of the `Navbar`
|
||||||
|
component specify some content (here, in the default slot). The `Navbar`
|
||||||
|
component can insert that content in its own template at the appropriate location.
|
||||||
|
An important information to notice is that the content of the slot is rendered in
|
||||||
|
the parent context, not in the navbar. As such, it can access values and methods
|
||||||
|
from the parent component.
|
||||||
|
|
||||||
|
Here is how the `Navbar` component could be defined, with the `t-slot` directive:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div class="navbar">
|
||||||
|
<t t-slot="default"/>
|
||||||
|
<ul>
|
||||||
|
<!-- rest of the navbar here -->
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Named slots
|
||||||
|
|
||||||
|
Default slots are very useful, but sometimes, we may need more than one slot.
|
||||||
|
This is what named slots are for! For example, suppose we implement a component
|
||||||
|
`InfoBox` that display a title and some specific content. Its template could look
|
||||||
|
like this:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div class="info-box">
|
||||||
|
<div class="info-box-title">
|
||||||
|
<t t-slot="title"/>
|
||||||
|
<span class="info-box-close-button" t-on-click="close">X</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-box-content">
|
||||||
<t t-slot="content"/>
|
<t t-slot="content"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
|
||||||
<t t-slot="footer"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
Slots are defined by the caller, with the `t-set-slot` directive:
|
And one could use it with the `t-set-slot` directive:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<div t-name="SomeComponent">
|
<InfoBox>
|
||||||
<div>some component</div>
|
<t t-set-slot="title">
|
||||||
<Dialog title="'Some Dialog'">
|
Specific Title. It could be html also.
|
||||||
|
</t>
|
||||||
<t t-set-slot="content">
|
<t t-set-slot="content">
|
||||||
<div>hey</div>
|
<!-- some template here, with html, events, whatever -->
|
||||||
</t>
|
</t>
|
||||||
<t t-set-slot="footer">
|
</InfoBox>
|
||||||
<button t-on-click="doSomething">ok</button>
|
|
||||||
</t>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example, the component `Dialog` will render the slots `content` and `footer`
|
## Rendering context
|
||||||
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.
|
The content of the slots is actually rendered with the rendering context corresponding
|
||||||
This is deprecated and should no longer be used in new code.
|
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).
|
||||||
|
|
||||||
## Reference
|
## Default Slot
|
||||||
|
|
||||||
### Default Slot
|
|
||||||
|
|
||||||
The first element inside the component which is not a named slot will
|
The first element inside the component which is not a named slot will
|
||||||
be considered the `default` slot. For example:
|
be considered the `default` slot. For example:
|
||||||
@@ -81,7 +102,19 @@ be considered the `default` slot. For example:
|
|||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Default content
|
One can mix default slot and named slots:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div>
|
||||||
|
<Child>
|
||||||
|
default content
|
||||||
|
<t t-set-slot="footer">
|
||||||
|
content for footer slot here
|
||||||
|
</Child>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Default content
|
||||||
|
|
||||||
Slots can define a default content, in case the parent did not define them:
|
Slots can define a default content, in case the parent did not define them:
|
||||||
|
|
||||||
@@ -96,12 +129,7 @@ Slots can define a default content, in case the parent did not define them:
|
|||||||
<!-- will be rendered as: <div><span>default content</span></div> -->
|
<!-- will be rendered as: <div><span>default content</span></div> -->
|
||||||
```
|
```
|
||||||
|
|
||||||
Rendering context: the content of the slots is actually rendered with the
|
## Dynamic Slots
|
||||||
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).
|
|
||||||
|
|
||||||
### Dynamic Slots
|
|
||||||
|
|
||||||
The `t-slot` directive is actually able to use any expressions, using string
|
The `t-slot` directive is actually able to use any expressions, using string
|
||||||
interplolation:
|
interplolation:
|
||||||
@@ -109,3 +137,102 @@ interplolation:
|
|||||||
```xml
|
```xml
|
||||||
<t t-slot="{{current}}" />
|
<t t-slot="{{current}}" />
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This will evaluate the `current` expression, and insert the corresponding slot
|
||||||
|
at the place of the `t-slot` directive.
|
||||||
|
|
||||||
|
## Slots and props
|
||||||
|
|
||||||
|
In a sense, slots are almost the same as a prop: they define some information
|
||||||
|
to pass to the child component. To make it possible to use it, and to pass it
|
||||||
|
down to sub component, Owl actually define a special prop `slots` that contains
|
||||||
|
all slot information given to the component. It looks like this:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{ slotName_1: slotInfo_1, ..., slotName_m: slotInfo_m }
|
||||||
|
```
|
||||||
|
|
||||||
|
So, a component can pass its slots to a subcomponent like this:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Child slots="props.slots"/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Slot params
|
||||||
|
|
||||||
|
For advanced usecases, it may be necessary to pass additional information to a
|
||||||
|
slot. This can be done by providing extra key/value pairs to the `t-set-slot`
|
||||||
|
directive. Then, the generic component can read them in its prop `slots`.
|
||||||
|
|
||||||
|
For example, here is how a Notebook component could be implemented (a component
|
||||||
|
with multiple page, and a tab bar, which only render the current active page,
|
||||||
|
and each page has a title).
|
||||||
|
|
||||||
|
```js
|
||||||
|
class Notebook extends Component {
|
||||||
|
static template = xml`
|
||||||
|
<div class="notebook">
|
||||||
|
<div class="tabs">
|
||||||
|
<t t-foreach="tabNames" t-as="tab" t-key="tab_index">
|
||||||
|
<span t-att-class="{active:tab_index === activeTab}" t-on-click="() => state.activeTab=tab">
|
||||||
|
<t t-esc="props.slots[tab].title"/>
|
||||||
|
</span>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
<div class="page">
|
||||||
|
<t t-slot="{{currentSlot}}"/>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
this.state = useState({ activeTab: 0 });
|
||||||
|
this.tabNames = Object.keys(this.props.slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentSlot() {
|
||||||
|
return this.tabNames[this.state.activeTab];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice how one can read the `title` value for each slots. Here is how one could
|
||||||
|
use this `Notebook` component:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Notebook>
|
||||||
|
<t t-set-slot="page1" title="'Page 1'">
|
||||||
|
<div>this is in the page 1</div>
|
||||||
|
</t>
|
||||||
|
<t t-set-slot="page2" title="'Page 2'" hidden="somevalue">
|
||||||
|
<div>this is in the page 2</div>
|
||||||
|
</t>
|
||||||
|
</Notebook>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Slot scopes
|
||||||
|
|
||||||
|
For other kind of advanced use cases, the content of a slot may depends on some
|
||||||
|
specific information specific to the generic component. This is the opposite
|
||||||
|
of the slot params.
|
||||||
|
|
||||||
|
To solve this kind of problems, one can use the `t-set-scope` directive along
|
||||||
|
with the `t-set-slot`. This defines the name of a variable that can access
|
||||||
|
everything given by the child component:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div>
|
||||||
|
<t t-set-slot="foo" t-set-scope="scope">
|
||||||
|
content
|
||||||
|
<t t-esc="scope.bool"/>
|
||||||
|
<t t-esc="scope.num"/>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
And the child component that includes the slot can provide values like this:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<div>
|
||||||
|
<t t-slot="foo" bool="other_var" num="5">
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|||||||
@@ -70,13 +70,13 @@ The component system in Owl requires additional directives, to express various
|
|||||||
needs. Here is a list of all Owl specific directives:
|
needs. Here is a list of all Owl specific directives:
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ------------------------ | --------------------------------------------------------------- |
|
| -------------------------------------- | --------------------------------------------------------------- |
|
||||||
| `t-component`, `t-props` | [Defining a sub component](component.md#sub-components) |
|
| `t-component`, `t-props` | [Defining a sub component](component.md#sub-components) |
|
||||||
| `t-ref` | [Setting a reference to a dom node or a sub component](refs.md) |
|
| `t-ref` | [Setting a reference to a dom node or a sub component](refs.md) |
|
||||||
| `t-key` | [Defining a key (to help virtual dom reconciliation)](#loops) |
|
| `t-key` | [Defining a key (to help virtual dom reconciliation)](#loops) |
|
||||||
| `t-on-*` | [Event handling](event_handling.md) |
|
| `t-on-*` | [Event handling](event_handling.md) |
|
||||||
| `t-portal` | [Portal](portal.md) |
|
| `t-portal` | [Portal](portal.md) |
|
||||||
| `t-slot` | [Rendering a slot](slots.md) |
|
| `t-slot`, `t-set-slot`, `t-slot-scope` | [Rendering a slot](slots.md) |
|
||||||
| `t-model` | [Form input bindings](input_bindings.md) |
|
| `t-model` | [Form input bindings](input_bindings.md) |
|
||||||
| `t-tag` | [Rendering nodes with dynamic tag name](#dynamic-tag-names) |
|
| `t-tag` | [Rendering nodes with dynamic tag name](#dynamic-tag-names) |
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user