How to bubble events up the slot chain without forward event handlers?

First I created this JSFiddle.

But here is the code:

<script type="text/x-template" id="slot-event-handler-template">
  <div @busy="busy = !!$event">
    <div>{{ busy ? 'Busy!' : 'Not Busy!' }}</div>
    <slot/>
  </div>
</script>

<script type="text/x-template" id="child-emitter-template">
  <div>
    <button @click="$emit('busy', true)">Make Busy</button>
    <button @click="$emit('busy', false)">Make Not Busy</button>
  </div>
</script>

<div id="app">
  <slot-event-handler>
    <child-emitter></child-emitter>
    <child-emitter></child-emitter>
    <child-emitter></child-emitter>
  </slot-event-handler>
</div>
const SlotEventHandler = {
  name: 'SlotEventHandler',
  template: '#slot-event-handler-template',
  data() {
    return {
      busy: false
    };
  }
};

const ChildEmitter = {
  name: 'ChildEmitter',
  template: '#child-emitter-template'
};

new Vue({
  el: "#app",
  components: { SlotEventHandler, ChildEmitter }
});

Currently using Vue 2.

The goal is that a component is able to listen for events from any child component in the “slot chain”. An example is, a parent element which handles a UI behavior such as showing busy status. Ideally, I wouldn’t have to create forward event handlers in the entire chain. To make it more complex there may be multiple instances of “slot-event-handler” on the page, so having a universal store somewhere wasn’t ideal. Since the focus is on the “slot-event-handler” and anything it’s “slot chain” I was hoping to achieve this simple behavior.

Is this possible?

Thanks!

When you say forwarding them up the chain are you referring to v-on="$listeners"?

Yeah, I think that could be a solution which may get there 95% of the way there. But in my sample I added:

<slot-event-handler v-on="$listeners">

But it doesn’t seem to be forwarding my emitted events. Does v-on="$listeners" only work for native events? That would be unfortunate for me.

Ideally, I could author <slot-event-handler> such that it would automatically add that v-on="$listeners" onto ever instance where it is declared.

Also, if v-on="$listeners" works for my scenario, does it work for an entire hierarchy? For example, what if I changed my sample to:

  <slot-event-handler v-on="$listeners">
    <third-party-component-with-slot>
      <child-emitter></child-emitter>
      <child-emitter></child-emitter>
      <child-emitter></child-emitter>
    </third-party-component-with-slot>
  </slot-event-handler>

Would it still work?

Thanks!

I have been reading more on v-on="$listeners" and it seems like the exact opposite of what I need. But I see why you referenced this, because it is a good way to bubble all events up. From what I understand v-on="$listeners" allows one to listen to all events, and forward those events to the current Vue instance’s $listeners. The $listeners are essentially event subscriptions of the parent, so this effectively bubbles up events.

But what I really want is to forward all events from all children in the slot hierarchy, down to a different child component. What I am looking for is like this:

  <div>
    <div>{{ busy ? 'Busy!' : 'Not Busy!' }}</div>
    <slot @busy.all="busy = !!$event" />
  </div>

This would allow me to handle ‘busy’ events which would occur from within the slot. Of course in the above code I am unable to put an event handler on a slot, and .all doesn’t exist. But it at least illustrates what I am looking for.

But after reading more up on $listeners, it seems like all events must be explicitly subscribed and they never automatically bubble up. Instead, each component in the chain must explicitly handle the event. Please let me know if that is incorrect.

I would be interested in any other design ideas in Vue for how I could achieve a similar pattern to what I am looking for. For example, what if my <slot-event-handler> registered itself in a custom library when it is created and instead of using emit, the custom library can be used by the child to ‘emit’ the request, of which the library would have to see if the caller has a <slot-event-handler> in the parent chain. Is that a bad pattern, why?

Thanks!