1

I have the following structure of Vue components:

<TopParent> <!-- listen for EventProducer's events here -->
  <Child_1>
    <Child_2>
      <Child_3>
        ... 
        <Child_N>
          <EventProducer /> <!-- emit events here --> 
        </Child_N>

      </Child_3>
    </Child_2>
  </Child_1>
</TopParent>

Question

I want to emit an event in <EventProducer> component and listen to the event in <TopParent> component?

How can I tell all the <Child_1>...<Child_N> components to just forward event to the parent?

P.S. I don't want to specify the exact names of the event, just to forward all of the events.


A stupid solution

In a very primitive way I could do it like this. But it very verbose, especially when there are more than 1 event:

<TopParent @foo="doTheJob()">
  <Child_1  @foo="emit('foo')">
    <Child_2  @foo="emit('foo')">
      <Child_3  @foo="emit('foo')">
        ... 
        <Child_N @foo="emit('foo')">
          <EventProducer @click="emit('foo')"/> 
        </Child_N>

      </Child_3>
    </Child_2>
  </Child_1>
</TopParent>

I believe there is a better way than this.

eXception
  • 1,307
  • 1
  • 7
  • 22
  • 1
    Use *Provide / Inject* https://vuejs.org/guide/components/provide-inject.html – Bin Rohan Mar 22 '23 at 12:22
  • @BinRohan Correct me, but provide/inject pass values from parent to child, not the way around (which is the case). Or I'm wrong? – eXception Mar 22 '23 at 12:44
  • You can inject an event bus or an object that needs to be changed, depending on what's foo is for – Estus Flask Mar 22 '23 at 13:59
  • 2
    [This question](https://stackoverflow.com/questions/63471824) has some good ideas for accomplishing what you want – yoduh Mar 22 '23 at 14:01
  • Like @yoduh said - use an event bus. Every component can emit events to the bus and every component can subscribe to the bus. If the component does not emit events to the bus but to itself - you will have to explicitly listen for the events that are interesting to you in the immediate parent of the component in question, and then re-emit those events to the event bus so that every other interested component can receive these events. – IVO GELOV Mar 22 '23 at 16:52

2 Answers2

2

there are a couple of ways to pass your data to child/parent component. Before implementation pay attention to what you need exactly

  1. Provide / Inject (can be global)
  2. store vuex; pinia (can be global)
  3. emit/props (just parent/child)
  4. useComposition (can be global)
// composition file 
import { ref } from 'vue'

const someString = ref<string>('')

export const useComposition = () => {
  return {
    someString,
  }
}
// usage 
import { useComposition } from 'path/to/file'
const { someString } = useComposition()
jovan
  • 29
  • 3
1

This can be achieved with provide/inject feature.

The idea is to provide a kind of "callback function" from TopParent to EventProducer.

Inside the TopParent component:

import { provide } from 'vue';

...
function activateOnEvent() {
  //...
}

provide('parentFn', activateOnEvent); //key, value

Inside the EventProducer component:

import { inject } from 'vue';
...
const parentFn = inject('parentFn');
...
<button @click="parentFn()">Click</button>

So, on your event you can directly call a function from the TopParent component.

eXception
  • 1,307
  • 1
  • 7
  • 22