I have my vue application using:
component-parent component that is made of component-child
inside component-parent I have buttons, when someone click a button I want to emit an event in order to be handled by vue and passed to another component
What I did so far:
var vm = new Vue({
el: '#app',
methods: {
itemSelectedListener: function(item){
console.log('itemSelectedListener', item);
}
}
});
Vue.component('component-child', {
template: ' <span v-on:click="chooseItem(pty )" >Button </span>',
methods: {
chooseItem: function(pty){
console.log(pty);
this.$emit('itemSelected', {
'priority' : pty
});
}
}
});
Vue.component('component-parent', {
template: '<component-child v-for="q in items" ></component-child>'
});
HTML:
<component-parent v-on:itemSelected="itemSelectedListener" ></component-parent>
It reaches my console.log(pty);
line but it seems that this.$emit('itemSelected'
wont get through:
console.log('itemSelectedListener', item); // this is not going to be called...
an hint?
should I bubble up the event from child->parent->Vue-instance? ( I also tried that but with no success)
Create a custome directive for bubbling and use it in the child component.
Sample directive:
Child component can use that directive to emit through the parent component (i switched to kabob case and shorthand for event).
Including my full bind directive below. It allows bubbling multiple events.
I'm a little surprised nobody suggested using an event bus component. It is a fairly common pattern in heavily decoupled systems to have a shared event bus, and then use it to link multiple disconnected components together pub/sub style.
Once you have one, it's simple to publish events from any place
And listen to them from somewhere else.
Note that the two components do not know anything about each other, and they don't really need to care how or why the event was raised.
There are some potentially undesirable side effects of this approach. Event names do need to be globally unique so that you don't confuse your app. You'll also potentially be channeling every single event through a single object unless you do something more sophisticated. You can do the cost / benefit analysis on your own app source to see if it's right for you.
In your child component, simply use
$emit
to send an event to the$root
like this:Then, in your parent component (eg: "App"), setup the listener in the Vue
mounted
lifecycle hook like this:There is one issue with your
component-parent
template as it tries to render multiple child components. Vue usually requires a single root div inside components therefore you need to wrap it in a div or other tag.A second thing to point out is that you emit an event from a child component which is 2 levels down and you listen to it in the root.
You have 2 options here. Either emit from
component-child
listen to that even incomponent-parent
then propagate that even upwards. Fiddle https://jsfiddle.net/bjqwh74t/29/The second option would be to register a global so called
bus
which is an empty vue instance that you can use for such cases when you want communication between non child-parent components. Fiddle https://jsfiddle.net/bjqwh74t/30/Usually between parent and child components you use the events directly by emitting from child and listening in parent with
v-on:event-name="handler"
but for cases where you have more levels between components you use the second approach.Doc link for the first case: https://vuejs.org/v2/guide/components.html#Using-v-on-with-Custom-Events
Doc link for the second case: https://vuejs.org/v2/guide/components.html#Non-Parent-Child-Communication
PS: prefer using kebab-case for event names which means you write with
-
instead of capital letters. Writing with capital letters can result in weird situations where your event is not caught in the root.It's a little bit late but here's how I did it:
component-child:
component-parent:
For what it's worth you can use the browser's event API. It requires a little more scripting than Vue's built-in stuff, but it also gets you around these bubbling issues (and is about the same amount of code as creating a "bus", as in the accepted answer).
On child component:
On parent component, in
mounted
lifecycle part: