Masade
Masade

Reputation: 716

Is there a way to capture events emitted by multiple child components in vuejs?

I have a parent component which has multiple child components

<grid>
   <cell></cell>
   <cell></cell>
   <cell></cell>
</grid>

My cell components emit an event with payload saying it is being edited this.$emit('editing',cellId)

I know I can capture the event like <cell @editing="do something"></cell> or capture using EventBus.$on('editing'), I do not want to use root listener as well this.$root.$on('editing')

But because its the parent component, how can i listen to event of 'editing' when the parent component is mounted

mounted: function(){
    this.$on('editing',dosomething)
}

why am I not able to add listen when the parent component is mounted?

Upvotes: 4

Views: 5535

Answers (3)

Andrey Popov
Andrey Popov

Reputation: 7510

The main difference that you are missing is described in the Custom Events section:

In addition, a parent component can listen to the events emitted from a child component using v-on directly in the template where the child component is used.

You cannot use $on to listen to events emitted by children. You must use v-on directly in the template, as in the example below.

What this means is that child-parent communication is done through a directive, using the v-on (or @edit) way.

Your example here

mounted: function(){
    this.$on('editing',dosomething)
}

Won't actually work. In the emit documentation it's said that:

Trigger an event on the current instance.

Which means that inside the same component, you can actually use this.$on and it will work. But if you want to use it in parent, then you should use the inline directive to have it bind, otherwise it won't work.

Also keep in mind that emits works only for a single step, meaning that the the parent can catch it. If you need to emit subchild -> child -> parent, then you should catch the event (using inline binding) from subchild in child, and re-emit it again so it goes to parent.

If it is outside of children-parent scope, then you should use what is called a global bus. Basically it narrows down everything to a single instance, which emits and listens for all events. So then they are no longer child-parent or whatever kind of connection, they are all on the very same instance, and therefore you can always use them in every component of yours.

Bottom line is - your approach to listen on mounted won't work. Hope that helps :)

Upvotes: 4

Geo C.
Geo C.

Reputation: 755

TL;DR Stumbled across this issue my self. Like the other said, when you want to bind an event listener from a parent, you need to use v-on because, well ... , you are binding something tot he child. So the actual callback is ran by the child, when that child detects that the event ocured.

In the child use this.$parent.$emit('event-name');
In the parent use

mounted: function() {
    this.$on('event-name', function() {console.log('test')});
}  

The above will let you trigger the event in the parent so you can use $on in the parent to lsiten to that event that was triggered by the child.

Upvotes: 0

V. Sambor
V. Sambor

Reputation: 13389

The difference between listening to each child and listening to the EventBus is this:

  • when you emit an event like this.$emit('event') the event will be fired only for the parent component.
  • when you do a EventBus like EventBus.$emit('event') then your event will be sent to all the components

There are pros and cons for each one; EventBus can send events to components which will never use that event (can become an event polution), and the parent event emitter can be not that elegant to use as EventBus.
So you decide which approach is good for you.

Upvotes: 1

Related Questions