I want to create a global event bus with Nuxt, (see here). My first instinct was to create a middleware like this:
export default function () {
let eventBus = new Vue();
return eventBus;
}
But I don't have access to the Vue instance in the middleware, I'm not sure where I can put the following code so I can emit and receive events across all pages/components.
I don't really want to import a file into every single component/page that uses the event bus, as it defeats the object of it being globally accessible. Anyone know a way I can achieve this?
Thanks!
You should define it in a plugin. Try this:
export default function ( {app, store} ){
app.$bus = new Vue
if (store) store.$bus = app.$bus
}
@motia Still getting a "Vue is not defined" error with this code too unfortunately.
@anthonycook is this not better to resolve with Vuex? Just as an idea though as I'm not familiar what you try to archive
@dohomi What I'm trying to do is get my child components to communicate with my parent components/pages. For example when I press a button in child component, the parent component will respond. From what I can gather from Vue's docs, custom events are the best way to do this. However, I can't seem to get them working with Nuxt.
hi, @anthonycook !
Maybe you forgot to import Vue?
import Vue from 'vue'
Hi, @anthonycook, I just tested the event bus and it works fine. Probably the solution is as @KonstantinVlasov suggests.
@KonstantinVlasov as I do similar things like you with a toolbar where users can press SAVE
I need to dispatch the click event down to a complete different component. I use a Vuex to toggle a Boolean variable like this:
state.js
export state = {
toggleSave: false
}
toolbar.js
dispatch('toggleSave', !this.$store.state.toggleSave)
some-random-component.vue
export default{
watch:{
'$store.state.toggleSave'(v){
// do something if toggleSave is changing
}
}
}
If you only need a parent child communication and not a global dispatch system you can pass events through your instance via this.$emit()
, this.$on()
and props
. See the doc.
If you're looking for a non parent-child communication, then go with vuex
.
I suggest Vuex
as well, but that's because I like to have well defined data flow patterns for my projects and not stray from the patterns. IE "we use Vuex to do this, so use Vuex, don't create a one-off event bus between two components", that way it's a bit easier contextually to understand what is going on. Less context switching. And donuts. Lots of donuts.
hello, i'm trying to create a event bus with this plugin:
`import Vue from 'vue'
export default function ({ app, store }) {
app.$bus = new Vue()
if (store) store.$bus = app.$bus
}`
In my nuxt config i have:
plugins: [
{ src: '~/plugins/event-bus' }
]
and in a component i'm trying to access the bus with this.$bus but is undefined. in this.$store.$bus is ok.
thank you
Why do you need to register the bus in the store? The store can easily replace a global bus emitter...
@Lacroute is not necessary in the store. i just copy the example of @motia
@javialon26 Ok I see.
The plugin let's you the opportunity to inject a piece of code in the root app. As the doc says, you'll be able to use this piece of code in middlewares
or fetch
and asyncData
hooks.
If you're looking for a global event dispatcher for your components, you should create an external file in assets
called bus.js
:
import Vue from 'vue'
const Bus = new Vue()
export default Bus
Then in your pages, or component simply import it with import Bus from '~/assets/bus'
. Then you'll be able to play with your custom events between your components. Be carefull, you'll bypass lots of good practices with the global bus way.
Again, I suggest you to take a look at vuex, it's not very complicated to understand, and your application will be more structured.
@Lacroute thank you, i understand vuex and actually im using it for auth, locale, menu state, etc. but in some case is more simple just fire an event.
playing with plugins, i found this solution for a global event bus:
`import Vue from 'vue'
const eventBus = {}
eventBus.install = (Vue) => {
Vue.prototype.$bus = new Vue()
}
Vue.use(eventBus)`
with this plugin i have access to this.$bus in all component. what do you think of this approach?
@valdinei use created instead of mounted
Hello!
I used the next configuration:
in plugins/eventBus.js
import Vue from 'vue'
const eventBus = {}
eventBus.install = function (Vue) {
Vue.prototype.$bus = new Vue()
}
Vue.use(eventBus)
in nuxt.config.js (into key "plugins". More info: https://nuxtjs.org/api/configuration-plugins)
module.exports = {
plugins: [ '~/plugins/eventBus.js' ]
}
in your component
methods:{
eventhandler(){
this.$bus.$emit('name-of-event', 'your-data')
}
}
in your other component
created () {
this.$bus.$on('name-of-event', (data) {
...
}
}
@AngelVasquezNep Thanks for the solution !
In the file plugins/eventBus.js
you create an a property named install
in the bus event object.
Is it recognized somewhere by vue or nuxt ?
@samyfox hi !
The property install
is a native method of Vue. It work in Vue and Nuxt.. More info: https://vuejs.org/v2/guide/plugins.html
Have a nice day ! 馃枛馃徑
This approach in Nuxt is causing memory leak, any clue?
If I replace
Vue.prototype.$bus = new Vue()
for
Vue.prototype.$bus = {
$on: function () {
},
$off: function () {
},
$emit: function () {
}
}
The memory leak is gone.
Thanks!
Code more simple, plugin:
import Vue from 'vue';
Vue.prototype.$bus = new Vue();
Use inject nuxt function
Create plugins/bus-inject.js
import Vue from 'vue';
export default (ctx, inject) => {
const bus = new Vue;
inject('bus', bus);
};
Register this plugin in nuxt.config.js
plugins: [
'~/plugins/bus-inject.js',
//or use this for browser using only
{src:'~/plugins/bus-inject.js', ssr: false}
]
Now it will be available in components, context and vuex
example-component.vue
export default {
mounted(){
this.$bus.$on('messageSent', e => console.log(e));
},
asyncData({app}){
//app.$bus available here also
}
}
store/index.js
export const state = () => ({
messages: []
});
export const actions = {
async sendMessage({commit}){
const message = (await this.$axios.post('/message', {text: 'hello'})).data;
commit('pushMessage', message);
this.$bus.$emit('messageSent');
}
};
export const mutations = {
pushMessage(state, message) {
state.messages.push(message);
this.$bus.$emit('messagePushed', message);
}
}
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Hello!
I used the next configuration:
in plugins/eventBus.js
in nuxt.config.js (into key "plugins". More info: https://nuxtjs.org/api/configuration-plugins)
in your component
in your other component