"Exploring the Power of Vue 3 Event Bus Through the Composition API

I recently set up mitt and I'm facing difficulties dispatching events to another component. The issue arises due to the absence of this in the setup() method, making it challenging to access the app instance.

Here's my current approach:

import App from './App.vue'
const el = document.getElementById('app')

import mitt from 'mitt';
const emitter = mitt();

const app = createApp(App)
app.config.globalProperties.emitter = emitter;
app.mount(el);

In the desired component, I aim to dispatch an event

export default {
   setup() {
      function toggleSidebar() {
          this.emitter.emit('toggle-sidebar');

          console.log(this); // binds to setup(), not the vue instance.
      }
   }
}

Due to the absence of this, accessing .emitter is not possible. What am I overlooking? How can I effectively utilize mitt in Vue 3 Composition API?


Interestingly, using v2 syntax allows me to access this.emitter. However, I'm keen on exploring the Composition API method.

export default {
  mounted() {
    console.log(this.emitter); // works
  }
} 

Answer №1

If you want to implement an event bus in Vue 3 Composition API, the process involves using Vue 3's latest provide API in your main.js file and then utilizing inject in any component:

1. Start by installing mitt:

npm install mitt

2. Providing the Event Bus:

Within main.js

import { createApp } from 'vue';
import App from './App.vue';

import mitt from 'mitt';                  // Import mitt
const emitter = mitt();                   // Initialize mitt

const app = createApp(App);
app.provide('emitter', emitter);          // ✅ Provided as `emitter`
app.mount('#app');

3. Injecting the Event Bus

3a. In Any Component - Emitting an event

import { inject } from 'vue'

export default {
  setup() {
    const emitter = inject('emitter'); // Inject `emitter`
    const mymethod = () => {
      emitter.emit('myevent', 100);
    };
    return {
      mymethod
    }
  }
}

You can call mymethod from a button click or similar events.

3b. In any Component - Listening for the event

import { inject } from 'vue'

export default {
  setup() {
    const emitter = inject('emitter');   // Inject `emitter`

    emitter.on('myevent', (value) => {   // *Listen* for event
      console.log('Received myevent!', `Value: ${value}`);
    });
  },
}

Console Output

Received myevent! Value: 100 

Answer №2

If you need to access the global property component, you can utilize the getCurrentInstance method:

Here is an example in JavaScript:

import { getCurrentInstance } from 'vue';
export default {
  setup() {
    // Retrieve current instance
    const internalInstance = getCurrentInstance(); 
    // Obtain emitter from the instance
    const emitter = internalInstance.appContext.config.globalProperties.emitter;
  }
} 

Answer №3

Up to this point, I've implemented the following code to provide access to the "emitter".

//main.ts
import mitt from 'mitt'
const emitter = mitt()
export default emitter

Within the components, I subsequently utilize

import emitter from '@/main';

So far, this approach has proven effective in both Vue2 and Vue3 - particularly with the options API.

However, I have encountered challenges when it comes to the new vite server and hot module reload (hmr). Is there a more optimal way to structure this?

Answer №4

To implement Event Bus with Composition API, follow these steps:

Start by installing and registering mitt in your app.js similar to how it is done below:

import App from './App.vue'
const el = document.getElementById('app')

import mitt from 'mitt';
const emitter = mitt();

const app = createApp(App)
app.config.globalProperties.emitter = emitter;
app.mount(el);

Next, organize the code for accessing the global emitter into a separate file named accessEmitter.js within the js/Composables folder:

import { getCurrentInstance } from 'vue';

export default function accessEmitter() {
    return getCurrentInstance().appContext.config.globalProperties.emitter;
}

Now you can use this functionality in your components:

<script setup>
import accessEmitter from '@/Composables/accessEmitter.js'
const emitter = accessEmitter();

// register listener
emitter.on("myEvent", (data) => {
    console.log('my event');
});
   
// remove listener
emitter.off("myEvent");

</script>

Answer №5

While @Dan's solution is effective, it may result in a 'emitter' is of type 'unknown' error in typescript. @acantepie has provided a solution for this issue which can be found here. The solution involves using a singleton class like so:

import mitt from "mitt";

export default mitt()

To use it:

import EventBus from "../lib/EventBus";
...

EventBus.emit(...)
EventBus.on(...)
...

Hopefully this will benefit someone in need like myself :)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having issues with UTF8 encoding when utilizing AJAX to send the complete HTML source in JavaScript

I'm encountering difficulties when trying to send a complete page source using AJAX. Despite attempting to escape the content with escape(), encodeURI(), and encodeURIComponent(), I cannot successfully transmit utf8 characters. Below is my code snipp ...

Clear the cache following the service call

I am currently working on a service that has two methods. Utilizing the built-in cache support for $resource, I am trying to implement a way to refresh the cache when a service call is made from the controller. I attempted to use $cacheResource without suc ...

How can I monitor and handle JavaScript errors without causing TestCafe tests to fail?

As I begin writing TestCafe tests, a problem arose on our website - a JS error in the console causing test failures. While it was satisfying to catch this issue, it also highlighted the fact that even minor JS errors could lead to test failures and hinder ...

Divide a string into separate numbers using JavaScript

This snippet of code is designed to search the table #operations for all instances of <td> elements with the dynamic class ".fuel "+ACID: let k = 0; let ac_fuel = 0; parsed.data.forEach(arrayWithinData => { let ACID = parsed.data[k][0]; ...

Substitute the comma with a space

Here is my input code snippet: (((text(text here))) AND (test3) Near (test4) NOT (test5) NOT (Test6)),((tttt,tttt)),((and,lol)),((hbhbhbhbhbh)) This is the output I get: (((text(text here))) AND (test3) Near (test4) NOT (test5) NOT (Test6) (tttt,tttt) (an ...

Set up authentication within a separate AngularJS module

I am struggling with how to develop a standalone login page for the BlurAdmin template found on GitHub. The main structure of the template is based on index.html, which includes header, footer, sidebar, and loads pages as templates using ui-view. However, ...

Show the outcome of a function inside an ng-repeat loop

I have encountered a roadblock in my Angular project. I am populating a table with run data retrieved from a REST call using ng-repeat. Each run includes GPS coordinates, and I have a function that converts these coordinates into the corresponding city nam ...

Transform a list separated by commas into an unordered list

Seeking a PHP, Jquery, or JavaScript method to convert comma-separated data into an unordered list. For clarification, I have uploaded a CSV file to WordPress where one section of content is separated by commas and I am looking to display it as a list. A ...

The Select2 ajax process runs twice

I am encountering an issue with a script I have that retrieves data from the backend to populate a select2 dropdown. The problem is that the ajax call is being triggered twice every time, which is not the desired behavior. I'm unsure of what mistake I ...

Three.JS: Utilizing a wireframe material for spheres with the EdgesHelper control

I'm exploring Three.JS for the first time and I have some doubts about whether it's the best tool for my current project. My goal is to create a wireframe material on a simple spherical geometry that looks like this: https://i.sstatic.net/WPfAh ...

When attempting to log a console statement using Vue Axios, an unexpected error occurs and returns an unexpected

My attempt to display jsonplaceholder posts using axios and vue is resulting in an unexpected console output that points back to the console.log statement. Check out the code snippet below: <script> import axios from 'axios'; export d ...

Issue with Angularjs: NG-repeat and filter not functioning correctly on array

After spending the last 3 hours searching on Google and Stack Overflow, I thought this would be easy, but I'm still stuck. I have a simple ng-repeat where I need to display everything from data2 that matches the unique ID in my data1's ref_id co ...

In JavaScript, when you update the property of a nested object within an array, the changes will also be applied to the same property for

Encountered an interesting issue in my code where updating a single property of a nested object within an array of objects results in all similar objects having the same property updated. Snippet of the Code: let financials = { qr: { controlData: [ ...

What could be causing React to render only the final two elements of my array?

I am currently working on a project where I need to display a series of images from a folder. While I have managed to accomplish this, I am facing an issue where the images are being displayed in rows of 2. Although the implementation is successful, it see ...

Steps for disabling script debugger within Visual Studio 2013

How do I disable script debugging in Visual Studio 2013? I have already disabled script JIT debugging under Tools>Options>Debugging>JIT, and have turned off script debugging in Internet Explorer as well. Despite setting the error option to 'b ...

Having trouble linking multiple components using redux in react native

I'm having trouble figuring out how to connect two different components using the redux store. Here's what I've attempted: View.js import React from 'react'; import {View, Text, Button} from 'react-native'; import {Act ...

Is it possible for a MUI control to automatically close itself when clicked outside of the component?

Currently diving into the world of MUI 5 component design. Does anyone know where I can locate the code responsible for closing a component when clicking outside of it? I've searched through the source code but couldn't pinpoint it. This functi ...

Tips for successfully implementing an Ocrad.js example

I've been working on an OCR (optical character recognition) web application and stumbled upon the Ocrad.js JavaScript library Ocrad.js. It seems like a perfect fit for what I need, but unfortunately, I'm having trouble getting it to function prop ...

Combining URLs in Angular 6 - A Step-by-Step Guide

How can I concatenate the commonUrl from CommonClass in Angular 6 for category.service.ts? common-class.ts export class CommonClass { constructor(public commonUrl : string = 'http://localhost:3000'){}; } category.service.ts import { CommonC ...

Error: Excessive recursion in Nuxt 3 module component

I am currently developing a Nuxt 3 module that includes a basic button component. The button is designed to toggle a boolean value when clicked, with the underlying logic stored in a separate file using pinia as a store. Here is an example of the store co ...