I have a Vue app like this:
<div id="example">
<event-emitting-component @clicked="methodOnRootInstance"></event-emitting-component>
<event-emitting-component-parent></event-emitting-component-parent>
<div v-for="click in clicks">
{{ click }}
</div>
</div>
And here is the JS for it:
// Child
Vue.component('event-emitting-component', {
template: '<div class="event-emitting-component" @click="$emit(\'clicked\')">Event emitter</div>'
});
// Parent
Vue.component('event-emitting-component-parent', {
template: '<div class="event-emitting-component-parent">' +
'A custom parent!'+
'<event-emitting-component></event-emitting-component>' + // <-- Please note child component
'</div>'
});
// create a root instance
new Vue({
el: '#example',
data: {
clicks : []
},
methods : {
methodOnRootInstance : function(){
this.clicks.push('Element clicked');
}
}
})
If you want to play with it it is also here:
https://codepen.io/EightArmsHQ/pen/QgbwPG?editors=1010
When you click the top child component a click is registered on the root element. Perfect.
When the child component is nested inside a parent (the second component in the example), obviously I can't add a @clicked="methodOnRootInstance"
as that method doesn't exist inside the component.
What is the best way to pass an event up through a number of nested components?
I've made a stripped back example here, but in reality some components are two or three levels deep. Is the answer (what I think it is) that inside the parent component I would have the following:
Vue.component('event-emitting-component-parent', {
template: '<div class="event-emitting-component-parent">' +
'A custom parent!'+
'<event-emitting-component @clicked="passClicked"></event-emitting-component>' + // <-- Please note child component
'</div>',
'methods': {
passClicked : function(){
this.$emit('clicked')
}
}
});
And then in the html template add the same:
<event-emitting-component-parent @clicked="methodOnRootInstance"></event-emitting-component-parent>
I know I can get it to work like this, however it doesn't seem very elegant. I've looked in the docs and there are functions such as sync
although I don't think it's what I need, I'm struggling to find the correct approach.
Bonus question: can vuex help with stuff like this?
This is the type of problem
vuex
is designed to solve, however, before you consider adding an extra layer of complexity to your app, you may be able to get away with a simple global event bus, which is simply an emptyVue
object to emit events onto, which can then be listened for by any component in your app, bypassing theparent-child
chain:Here's the JSFiddle: https://jsfiddle.net/oatLhzLp/