You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Even after the spec changes in #571, it's still not exactly obvious how to detect final distribution and ignore intermediary slotting (an element being slotted to a slot does not mean that's where the element is finally distributed to).
I asked and answered my own question on how to achieve the desired effect using slotchange and assignedNodes()/assignedElements() here:
A possible idea is that a distributionchange event (or distribution event, name bike sheddable)
would not bubble
would fire on any slots in a chain of slots (slot assigned to a slot assigned to a slot, where an element might tunnel these slots to its final distributed destination) only if final distribution to those slots changed.
event.target is always the slot that the event fires on, and event.target is always === event.currentTarget because there is no bubbling.
With that in place, people could call slot.distributedNodes() or distributedElements() in the event handler and
if the slot is assigned to another slot (assignedSlot is not null), then it must have no distributed nodes, so the return value is an empty [].
if the slot is assigned to another slot, it means that this slot was just slotted to a further slot, hence the result of distributed* API calls was previously not empty, but is now empty.
if the slot is not assigned to another slot, it must be the final distribution location of nodes or elements, so calling distributed* APIs on this slot will return a non-empty array (unless node or elements higher up were removed or slot atributes changed).
If there is a chain of 2 slots (across two shadow trees), and then the deeper 2nd slot is slotted to an even deeper 3rd slot in a 3rd deeper shadow tree, then distributionchange would fire only on the 2nd and 3rd slots, because no distribution changed for the 1st slot in the ancestor-most shadow tree. The only distribution change that happened is that elements went from being distributed to the 2nd slot location to now being distributed to the deeper 3rd slot location, so the event would fire for those two slots only. If more shadow roots are added between slots 2 and 3 and connect the slot distribution chain, no distributionchange events would fire because the final deepest slot is still the final place where nodes or elements are still distributed to.
It's a bit difficult to describe all this with words. so here is an example of code using slotchange and assignedNodes, and how the equivalent would be using distributionchange and distributedNode:
Current approach with slotchange and assigned* APIs:
// Assume this slotchange handler will be added to all slots in a hierarchy of shadow trees.constslotchangeEventHandler=event=>{// Always use `event.currentTarget` because that points to the slot// that this event handler is on, whereas `event.target` will// always point to the slot from the ancestor-most shadow tree.// That ancestor-most tree's slot is slotted to this slot (currentTarget)// or to some other slot that is ultimately distributed to this slot.constslot=event.currentTarget// Note, by using `currentTarget`, we effectively don't care about bubbling.// Also note that event delegation would be useless here, because `currentTarget` would be// the delegating element, and `target` would be the ancestor-most slot and never the// distribution slot, therefore neither is useful for the case of detecting final distribution.// Hence my suggestion of `distributionchange` not bubbling.// If the slot has an `assignedSlot`, then it can not possibly be the slot// where nodes or elements are finally distributed to, so return an empty// array in that case. Otherwise, the slot must be the final distribution// slot, in which case calling `assignedNodes` with `flatten:true` will give// the desired result (the finally-distributed nodes).constdistributedNodes=slot.assignedSlot ? [] : slot.assignedNodes({flatten: true})// Similar if you just want elements (f.e. not text nodes):constdistributedElements=slot.assignedSlot ? [] : slot.assignedElements({flatten: true})})
Here is the same result using distributionchange and the distributed* APIs:
// Assume this distributionchange handler will be added to all slots in a hierarchy of shadow trees.constdistributionchangeEventHandler=event=>{// Either one works, target and currentTarget are the same: the slot on which distribution changed:// People can't get this wrong, whereas with slotchange they which can lead to confusion and broken expectations.constslot=event.target// No need to think here, no need to add conditional logic, no need to set flatten to true, whereas// with slotchange it is easy to get this wrong:constdistributedNodes=slot.distributedNodes()// Similar if you just want elements (f.e. not text nodes):constdistributedElements=slot.distributedElements()})
As you can see, the distributionchange + distributed* API approach is simpler, and is easy to get right. With slotchange and assigned* APIs, it's harder to get right; easy to get detection of final distribution wrong.
In a real-world project I'm working on, I only care about final distribution of nodes and elements, in order to render based on the composed tree using WebGL. In particular, I need to know when final distribution changes so that I can re-parent the objects that represent what to draw in WebGL, and the tree structure of WebGL objects therefore matches that of the DOM composed tree.
The text was updated successfully, but these errors were encountered:
Even after the spec changes in #571, it's still not exactly obvious how to detect final distribution and ignore intermediary slotting (an element being slotted to a slot does not mean that's where the element is finally distributed to).
I asked and answered my own question on how to achieve the desired effect using
slotchange
andassignedNodes()
/assignedElements()
here:https://stackoverflow.com/questions/69078150
A possible idea is that a
distributionchange
event (ordistribution
event, name bike sheddable)event.target
is always the slot that the event fires on, andevent.target
is always=== event.currentTarget
because there is no bubbling.With that in place, people could call
slot.distributedNodes()
ordistributedElements()
in the event handler andassignedSlot
is not null), then it must have no distributed nodes, so the return value is an empty[]
.distributed*
API calls was previously not empty, but is now empty.distributed*
APIs on this slot will return a non-empty array (unless node or elements higher up were removed or slot atributes changed).If there is a chain of 2 slots (across two shadow trees), and then the deeper 2nd slot is slotted to an even deeper 3rd slot in a 3rd deeper shadow tree, then
distributionchange
would fire only on the 2nd and 3rd slots, because no distribution changed for the 1st slot in the ancestor-most shadow tree. The only distribution change that happened is that elements went from being distributed to the 2nd slot location to now being distributed to the deeper 3rd slot location, so the event would fire for those two slots only. If more shadow roots are added between slots 2 and 3 and connect the slot distribution chain, nodistributionchange
events would fire because the final deepest slot is still the final place where nodes or elements are still distributed to.It's a bit difficult to describe all this with words. so here is an example of code using
slotchange
andassignedNodes
, and how the equivalent would be usingdistributionchange
anddistributedNode
:Current approach with
slotchange
andassigned*
APIs:Here is the same result using
distributionchange
and thedistributed*
APIs:As you can see, the
distributionchange
+distributed*
API approach is simpler, and is easy to get right. Withslotchange
andassigned*
APIs, it's harder to get right; easy to get detection of final distribution wrong.In a real-world project I'm working on, I only care about final distribution of nodes and elements, in order to render based on the composed tree using WebGL. In particular, I need to know when final distribution changes so that I can re-parent the objects that represent what to draw in WebGL, and the tree structure of WebGL objects therefore matches that of the DOM composed tree.
The text was updated successfully, but these errors were encountered: