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)provided by the parent and injected 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