Is there a way to allow events to bubble up when using a component within a component?
My application is a dynamic menu. The dynamic menu is a component (dyn-m
There are 4 options I know of
this.$parent
(repetitively) on the child component to access the desired parent and emit the event. (see "Implement your own bubbling event plugin" below)provide
d by the parent and inject
ed in the children.It's very simple. The plugin adds a new $bubble
method that emits events that bubble to their parents. I considered publishing a plugin that does this, but it's so simple that the overhead is not worth it.
// Add this as a Vue plugin
Vue.use((Vue) => {
Vue.prototype.$bubble = function $bubble(eventName, ...args) {
// Emit the event on all parent components
let component = this;
do {
component.$emit(eventName, ...args);
component = component.$parent;
} while (component);
};
});
// Some nested components as an example
// note usage of "$bubble" instead of "$emit"
Vue.component('component-c', {
template: `
`,
});
Vue.component('component-b', {
template: ` `,
methods: {
onMyEvent(...args) {
console.log('component-b listener: ', ...args);
},
},
});
Vue.component('component-a', {
template: ` `,
methods: {
onMyEvent(...args) {
console.log('component-a listener: ', ...args);
},
},
});
var vapp = new Vue({
el: '#app',
methods: {
onMyEvent(...args) {
console.log('root listener: ', ...args);
},
},
});
The event bus looks like this:
Vue.component('dyn-menu', {
components: {
'menu-item': {
template: '- {{item.text}}
',
props: ['item'],
inject: ['eventBus'], // <-- Inject in the child
methods: {
itemClick() {
// Emit the event on the event bus
this.eventBus.$emit('dyn-menu-item-click', ['menu-item dyn-menu-item-click']);
}
}
}
},
// ...
});
var vapp = new Vue({
el: '#app',
data: {
// ...
eventBus: new Vue(),
},
provide() {
return {
// The parent component provides the event bus to its children
eventBus: this.eventBus,
};
},
created() {
// Listen to events on the event bus
this.eventBus.$on('dyn-menu-item-click', this.menuClick);
},
methods: {
menuClick(message) {}
}
})
Working example: https://jsfiddle.net/7vwfx52b/
There are plenty of event bus plugins listed here: https://github.com/vuejs/awesome-vue#custom-events