How to use global events in Vue.js and Nuxt

Last updated

Antonio Ufano avatar

Antonio Ufano

After a few years of building web apps with Vue.js and Nuxt, I recently found a specific scenario in which I needed to send an event from a child component and listen to it in multiple places throughout my app. Here is what I found about this and how I solved it.

What is a global event

A global event is a type of event that is emitted from a component and that can be captured by any other component of your app. Normally you emit events from a child component and capture them from its parent. Let's review a scenario in which we can use global events.

Scenario to use global events

I have a navigation bar component with a login button. This component NavBar.vue is part of the application template. Then I have multiple pages and in one of them, I have dynamic data depending on if a user is logged in or not. The tricky part is that the NavBar.vue component is not included in the Page.vue views so I can not use the default $emit. In addition, as the NavBar.vue component is part of the application layout, users can log in from any page and after the Page.vue view has been loaded, so I can't just check if the user is logged in on the mounted or created hooks 😕

The examples above are valid for Vue.js 2.x only. If you're using Vue.js 3.x, check the documentation for alternatives.

How to emit global events in Vue.js

I'll consider we have the NavBar.vue component from which I need to emit the event and a Page.vue view in which I have to capture it. As explained above, these are not parent/child related so we can't use the default $emit.

First, create a file named GlobalEventEmitter.js in your project with the code below:

// /utils/GlobalEventEmitter file

import Vue from 'vue'
export const GlobalEventEmitter = new Vue()

Note: I like to include these type of files in a utils folder

As you can see this is just another Vue instance. Now, import this file in the component that will emit the global event, in my case NavBar.vue:

// NavBar.vue file
<template>
  <nav>
    <button @click="handleLogin()">Sign in with Google</button>
  </nav>
</template>

<script>
import { GlobalEventEmitter } from '@/utils/GlobalEventEmitter'

export default {
  data() {
    return {
      // any component data
    }
  },

  methods: {
    handleLogin() {
      // logic to login user...

      // emit global event, captured in other views
      GlobalEventEmitter.$emit('userLoggedIn')
    },
  },
}
</script>

To capture the event in the Page.vue view, we have to import the globalEventEmitter as well and create the event listener for the userLoggedIn event on the created lifecycle hook using the $on directive:

// Page.vue file
<template>
  <div>
    <div v-if="loggedIn">Content for not logged users</div>
    <div v-else>Content for authenticated users</div>
  </div>
</template>

<script>
import { GlobalEventEmitter } from '@/utils/GlobalEventEmitter'

export default {
  data() {
    return {
      loggedIn: false,
    }
  },

  created() {
    // adds the event listener function that will handle the event
    GlobalEventEmitter.$on('userLoggedIn', () => {
      console.log(`A user has logged in!`)
      this.loggedIn = true
    })
  },
  beforeDestroy() {
    // removes event listener
    GlobalEventEmitter.$off('userLoggedIn', userLogged)
  },
}
</script>

When the page is created, we're creating the event listener that will react to the userLoggedIn event and execute the callback function on it. In the example above, just write a message in the console and update the loggedIn flag from the view data.

We're also removing the event listener on the beforeDestroy lifecycle hook.

How to emit global events in Nuxt.js

With Nuxt this is much simpler. We don't need to create our own global event emitter as we can use the global $nuxt object to emit and capture the global events.

Following the same example as above we'll emit the event right after the user logs in:

// NavBar.vue file
<template>
  <nav>
    <button @click="handleLogin()">Sign in with Google</button>
  </nav>
</template>

<script>
export default {
  data() {
    return {
      // any component data
    }
  },

  methods: {
    handleLogin() {
      // logic to login user...

      // emit global event, captured in other views
      this.$nuxt.$emit('userLoggedIn')
    },
  },
}
</script>

Now we can capture this event in our page by creating an event listener on the created hook:

// Page.vue file
<template>
  <div>
    <div v-if="loggedIn">Content for not logged users</div>
    <div v-else>Content for authenticated users</div>
  </div>
</template>

<script>

export default {
  data() {
    return {
      loggedIn: false,
    }
  },
  created() {
    // adds the event listener function that will handle the event
    this.$nuxt.$on('userLoggedIn', () => {
      console.log('User logged in!')
      // do something...
      this.loggedIn = true
    })
  }
  beforeDestroy() {
    // removes event listener
    this.$nuxt.$off('userLoggedIn')
  },
}
</script>

And we're also deleting the event listener on the beforeDestroy lifecycle hook 😉

Summary

As you can see, we're using vanilla javascript events and event listeners (which is what Vue uses under the hood). Global events are a good solution but most of the times you can use other alternatives like: global storage or Vuex or maybe structuring your components and views in a different way. In my case, I didn't wanted to refactor the whole project but keep in mind that there are always multiple ways to code things.

Hope you find this useful.

Happy coding ✌️

If you enjoyed this article consider sharing it on social media or buying me a coffee ✌️

Oh! and don't forget to follow me on Twitter where I share tons of dev tips 🤙

Other articles that might help you

my projects

Apart from writing articles in this blog, I spent most of my time working on my personal projects.

lifeboard.app logo

theLIFEBOARD.app

theLIFEBOARD is a weekly planner that helps people achieve their goals, create new habits and avoid burnout. It encourages you to plan and review each week so you can easily identify ways to improve your productivity while keeping track of your progress.

Sign up
soliditytips.com logo

SolidityTips.com

I'm very interested in blockchain, smart contracts and all the possiblilities chains like Ethereum can bring to the web. SolidityTips is a blog in which I share everything I learn about Solidity and Web3 development.

Check it out if you want to learn Solidity
quicktalks.io logo

Quicktalks.io

Quicktalks is a place where indie hackers, makers, creators and entrepreneurs share their knowledge, ideas, lessons learned, failures and tactics they use to build successfull online products and businesses. It'll contain recorded short interviews with indie makers.

Message me to be part of it