Amrit Kahlon
Amrit Kahlon

Reputation: 1916

How do you emit an event from a nuxt plugin?

I am creating a plugin that will emit basic nuxt events triggered by sockets. The nuxt event will then be recieved and open a snackbar. When inside a component it is easy to send and receive events by using $nuxt

this.$nuxt.$on('open-snackbar', this.handler)
this.$nuxt.$emit('open-snackbar', options)

However how I'm trying to do this in a plugin so its not tied to any one page, but exists throughout the app. I can't seem to figure out how to emit it from said plugin:

export default (context) => {
    console.log(context)
    console.log(context.$emit)
    console.log(context.emit)
    console.log(context.$nuxt)
    console.log(context.app.emit)
    console.log(context.app.$nuxt)
}

context.app seems like it would be the correct object but it doesn't seem to work. Any ideas?

Upvotes: 8

Views: 16298

Answers (3)

You can use something like this in your plugin.js file, what the plugin will do is use window.$nuxt.$emit which is available on the client side

export default function (context) {
    $nuxt.$emit('event-to-emit')
}

Upvotes: 7

Edmund1645
Edmund1645

Reputation: 349

I figured another way to do it, by creating a manual event bus using Vue itself and using combined inject

In my case, I had a global axios interceptor to check the responses for a status code of 401, meaning that the user's session has expired and then display a notification to them.


// my-plugin.js
import Vue from 'vue'

export default function ({ $axios, app }, inject){

  inject('eventHub', new Vue()); // this is the same as Vue.prototype.$eventHub = new Vue()

  // checking for status 
    $axios.onError((error) => {
    const code = parseInt(error.response && error.response.status)
    if (code === 401) {
      app.$auth.logout() // logout if errors have happened
      app.$eventHub.$emit('session-expired')
    }
  })
}

The event bus is now accessible both in context and in any Vue instance

// login.vue

export default{
  data(){
    // data
  },
  created(){
    this.$eventHub.$once('session-expired', ()=> {
    this.showAlert()
  })
  },
  methods: {
    showAlert(){
      // display notifcations
    }
  }
}

Upvotes: 1

Amrit Kahlon
Amrit Kahlon

Reputation: 1916

It's not the solution I was looking for, but as a workaround I injected another instance of vue as a plugin to use as an event bus. It doesn't use the nuxt context as I initially wanted, but it works.

import Vue from 'vue'

export const bus = new Vue()

export default (_context, inject) => {

    // Client only
    if (process.client) {
        // Event bus for plugins
        inject('bus', bus)
    }
}

/**
 * Socket that pops open a snackbar
 */
export default ({ app: { $bus, $sockets } }) => {

    // Incoming message
    $sockets.on('message', payload => {

        // When we are on the messages page with the user
        if (window.location.pathname === `/messages/${payload.message.sender.username}`) {
            $bus.$emit('message-conversation', payload)
        }
        // Elsewhere, or messages with a different user
        else {
            $bus.$emit('open-snackbar', {
                body: payload.message.body,
                link: `/messages/${payload.message.sender.username}`,
                user: payload.message.sender
            })
        }
    })

    // Incoming notification
    $sockets.on('notification', payload => {
        $bus.$emit('open-snackbar', {
            body: payload.notification.text,
            link: payload.notification.link || '/notifications',
            user: payload.notification.source
        })
    })
}

Upvotes: 0

Related Questions