Technical Articles relating to Oracle Development Tools and Frameworks

  • JET
    February 3, 2017

JET Custom Components IX - Advanced Slotting

Duncan Mills

Last Updated Jan 2020 for JET 8


In the previous article, I introduced slotting and showed how it can be used to inject external content into specific places within your Custom Components. In this article we'll look at some more advanced topics that relate to the use of components with slots, specifically:

  • Nesting
  • Looping
  • Slotting and the Lifecycle

Nested Components

There is no restriction as to what elements you can assign inside of a component slot and therefore it follows that it's going to be possible to nest your Custom JET Components, and indeed this extends to nesting the same type of component with exactly the same set of slots. For example, imagine that I have two components, ccdemo-component-1 and ccdemo-component-2 where each component defines an <oj-bind-slot> with a name of content. These would all be valid combinations:

Example 1
<!--Slot containing just a span, we've seen this before-->
<ccdemo-component-1 value={{name}}>
  <span slot="content">Component 1 Content</span>


Example 2
<!--Slot containing a different CCA-->
<ccdemo-component-1 value={{name}}>
  <ccdemo-component-2 value={{name}} slot="content">
    <span slot="content">Component 2 Content</span>


Example 3
<!--Slot containing another Instance of the same CCA-->
<ccdemo-component-1 value={{name}}>
  <ccdemo-component-1 value={{name}}  slot="content">
    <span slot="content">Inner Component 1 Content</span>

The key things to understand with all three variants are:

  1. How each slot is actually allocated
  2. What the binding expressions reference

Looking at the slot management issue first of all. The rule here is pretty simple, any slot attribute is scoped to the component that is the immediate parent of the element with slot defined. It is not possible for an element to "jump generations" and have itself allocated to any ancestor component's slot apart from that of its immediate parent. This even extends to the case where an element is allocated a slot name which it's immediate parent does not recognize but its grandparent does. In this case the content allocated to that slot would not be displayed because its (immediate) parent component does not recognize it.

On the issue of binding scope, nested components are all treated as siblings. In Example 2 above, both ccdemo-component-1 and ccdemo-component-2 will be bound to the same source observable name in the common parent view that contains this markup. Put another way, the inner component does not gain access to the viewModel of the outer component, that remains private.

Sharing Information between Nested Components

As stated above, a nested component does not have magical access to its parent's viewModel. So should you need to share information between them then introducing a common context object in the shared top level viewModel is probably the best way. This context object can then be supplied to both the parent component and the child/children via a bound property ({{...}}) on each.

However, If you have a use case where you do need to pass information between components in this way, then perhaps slotting is not the way that they should be combined. In later articles I'll be discussing how to manage deferred UI creation and also how to communicate between components in a loosely coupled fashion. These may both be better strategies in many cases.

Multiple Nodes in a Slotting

In the previous article in this series I noted how you can assign multiple child nodes to the same slot. Something like:

<ccdemo-name-badge badge-name="{{personName}}" 
  <span slot="greetingArea">Hello</span>
  <div slot="greetingArea">
    <span>I &hearts;</span>
    <img src="images/oracle_jet_icon.png" 

If you do this, then as I mentioned, both DOM nodes will be relocated into the designated slot position in the order that they are defined. However, you can exercise a little more finesse here.

The <oj-bind-slot> tag that you use within the custom component view template to indicate where to place slot content, actually supports an additional attribute as well as the name attribute that we saw before. The extra attribute is called index. The index attribute allows you to refer to the nodes that have been defined by the component consumer as belonging to this slot. So for example we might have a simple HTML template for the Composite component like this:

  <oj-slot name="content" index="0"/>
  <oj-slot name="content" index="1"/>

And the consumer might use this component thus:

  <p slot="content">Hello</p>
  <p slot="content">Goodbye</p>
  <p slot="content">This will not be rendered</p>

The result would be that the text Hello would end up above the <hr> line and the Goodbye would be below. As indicated the third node is not referenced by the template and so would be ignored.

Slotting and Looping

You can use slot references within a looping construct in your custom JET component view HTML template, but only in a very specific way. It is not, for example, possible to do this:

<oj-bind-for-each data="[[myItems]]">
    <div class="oj-panel">
      <oj-bind-slot name="item"></oj-bind-slot>

This is because we can't place a slotting marker in more than one place and implicitly the above would try and place one instance of the marker per-row in the loop.

However, we can reference the same slot multiple times if we use both name and index attributes

<oj-bind-for-each data="[[myItems]]">
    <div class="oj-panel">
      <oj-bind-slot name="item" index="[[$current.index]]"></oj-bind-slot>

Now rather than trying to put the same content in multiple places, we're specifically placing indexed slot children in different places which is allowed. Note that you need to be cautious here, of course, to ensure that the number of DOM nodes supplied by the consumer matches the number of loop iterations that you will go through. Otherwise, in this case, you'd be stamping out empty panels or similar.

Slotting and the Lifecycle

In the context of the component lifecycle there are two sub-topics to look at:

  1. Discovering what slots are in use
  2. What happens to the DOM during slotting

What Slots are in Use?

If you refer back to the main article on lifecycle you will see that the context object that is passed to the various lifecycle methods contains an object called slotCounts. This  has a property for each slot name that the consumer has referred to, and the value of that property is the number of DOM nodes that are allocated to that slot. This then is useful information for the component to understand what the user has specified in terms of the advertised slots, for example in the looping scenario as discussed above.

Slotting and the DOM

As you can imagine, internally the component needs to rearrange DOM nodes in the view to weave the correct nodes into the designated slot positions defined by the view template. Looking back at the lifecycle article again, I stated that (for example) during the activated phase of the lifecycle, the child DOM within the Custom JET Component is empty and does not get populated until connected. This was not strictly true. In fact, during the activated phase (and earlier), if the component consumer has defined child elements for placement into slots, then those nodes will be present in the DOM as direct children of the component. When you get to the initial connected phase of the lifecycle you will find that the nodes have disappeared as direct children of the component. They have, in face, just been temporarily shunted off into a holding area. Finally, when you get to the bindingsApplied phase the nodes will be positioned in their new homes based on the <oj-bind-slot> markers in the template.

Yet More on Slotting... 

Yes there is more, specifically a topic I alluded to in the first article about slotting and that's a consideration of how slotted content can actually access information from the custom components viewModel state. This is possible using a feature called template slots which where introduced in JET 5 - you can jump there directly now if you are on a slotting junket.

What's Next?

We've now covered all of the core elements of Custom JET Component creation, covering properties, methods, events and slotting. The next couple of topics round out the story with some more advanced techniques, starting out with custom property parsing.

JET Custom Component Series

If you've just arrived at Custom JET Components and would like to learn more, then you can access the whole series of articles on the topic from the Custom JET Component Learning Path

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.