Slot Binding
The oj-bind-slot element is used inside a composite View as a placeholder for child DOM and is
a declarative way to define a slot.
Default markup can be defined if no child DOM is assigned to that particular
slot by adding the markup as children of the slot. An oj-bind-slot element with a name attribute
whose value is not the empty string is referred to as a named slot. A slot without a name attribute or one
whose name value is the empty string is referred to as the default slot where any composite
children without a slot attribute will be moved to.
Slot Properties
- A default slot is a slot element whose slot name is the empty string or missing.
- More than one node can be assigned to the same slot.
- A slot can also have a slot attribute and be assigned to another slot.
- A slot can have fallback content which are its child nodes that will be used in the DOM in its place if it has no assigned nodes.
- A slot can also also have an index attribute to allow the slot's assigned nodes
to be individually slotted (e.g. in conjunction with an oj-bind-for-each element).
Assignable Node Properties
- Nodes with slot attributes will be assigned to the corresponding named slots (if
present) and all other assignable nodes (Text or Element) will be assigned to
the default slot (if present).
- The slot attribute of a node is only applied once. If the View contains a
composite and the node's assigned slot is a child of that composite, the slot
attribute of the assigned slot is inherited for the slotting of that composite.
- Nodes with slot attributes that reference slots not present in the View will not appear in the DOM.
- If the View does not contain a default slot, nodes assigned to the default slot will not appear in the DOM.
- Nodes that are not assigned to a slot will not appear in the DOM.
Example #1: Basic Usage
Note that the IDs are provided for sample purposes only.
Initial DOM
<component-a>
<div id="A" slot="foo"></div>
<div id="B" slot="bar"></div>
<div id="C"></div>
<div id="D" slot="foo"></div>
<div id="E" slot="cat"></div>
</component-a>
View
<!-- component-a View -->
<div id="outerFoo">
<oj-bind-slot name="foo"></oj-bind-slot>
</div>
<div id="outerBar">
<oj-bind-slot name="bar"></oj-bind-slot>
</div>
<div id="outerBaz">
<oj-bind-slot name="baz">
<!-- Default Content -->
<img id="F"></img>
<div id="G"></div>
</oj-bind-slot>
</div>
<div id="outerDefault">
<oj-bind-slot>
<!-- Default Content -->
<div id="H"></div>
</oj-bind-slot>
</div>
Final DOM
<component-a>
<div id="outerFoo">
<div id="A" slot="foo"></div>
<div id="D" slot="foo"></div>
</div>
<div id="outerBar">
<div id="B" slot="bar"></div>
</div>
<div id="outerBaz">
<img id="F"></img>
<div id="G"></div>
</div>
<div id="outerDefault">
<div id="C"></div>
</div>
</component-a>
Example #2: Slot Attribute Evaluation
When a node is assigned to a slot, its slot value is not used for subsequent
slot assignments when child bindings are applied. Instead that slot's slot attribute,
which by default is "", overrides the assigned node's slot attribute. No actual
DOM changes will be made to the assigned node's slot attribute, but its evaluated
slot value will be managed internally and used for applying subsequent child bindings.
Initial DOM
<component-a>
<div id="A" slot="foo"></div>
</component-a>
View
<!-- component-a View -->
<component-b>
<oj-bind-slot name="foo"></oj-bind-slot>
</component-b>
<!-- component-b View -->
<div id="outerFoo">
<oj-bind-slot name="foo"></oj-bind-slot>
</div>
<div id="outerDefault">
<oj-bind-slot></oj-bind-slot>
</div>
When applying bindings for the component-a View, the oj-bind-slot binding will replace
slot foo with div A. Slot foo's slot attribute ("") overrides div A's ("foo")
so that the evaluated slot value ("") will be used when applying subsequent child bindings.
<!-- DOM -->
<component-a>
<!-- Start component-a View -->
<component-b>
<!-- Evaluated slot value is "" -->
<div id="A" slot="foo"></div>
</component-b>
<!-- End component-a View -->
</component-a>
When applying bindings for the component-b View, the oj-bind-slot binding will replace
component-b's default slot with div A since it's evaluated slot value is "".
<!-- DOM -->
<component-a>
<!-- Start component-a View -->
<component-b>
<!-- Start component-b View -->
<div id="outerFoo">
</div>
<div id="outerDefault">
<div id="A" slot="foo"></div>
</div>
<!-- End component-b View -->
</component-b>
<!-- End component-a View -->
</component-a>
Deferred Slots
As a performance enhancement, the composite can participate in deferred slot
rendering by conditionally rendering a slot element inside a conditional oj-bind-if element
and document that certain slots will be lazily rendered. This gives the application the opportunity
to wrap their slot content in an
oj-defer element and have the
bindings for that deferred content be delayed. oj.Components.subtreeHidden/Shown will automatically
be called on the slot contents when they are added or removed from a slot.
Note that due to a current
limitation, the slot element should be wrapped in an HTML element (e.g. <div> or <span>), when it is a child of an
oj-bind-if element or a knockout if binding on a comment node. It is not required to wrap when
the slot element is a child of a knockout if binding on an HTML element.
Initial DOM
<card-component>
<oj-defer slot="front">
<div>
...
</div>
</oj-defer>
<oj-defer slot="back">
<div>
...
</div>
</oj-defer>
</card-component>
View
<oj-bind-if test="isFront">
<div>
<oj-bind-slot class="card-component-front">
...
</oj-bind-slot>
</div>
</oj-bind-if>
<oj-bind-if test="!isFront">
<div>
<oj-bind-slot class="card-component-back">
...
</oj-bind-slot>
</div>
</oj-bind-if>