Mahma Deva
Mahma Deva

Reputation: 566

Call event bus with this.$root.$emit

I have a simple Event bus that changes styles on a page and it works. The event bus is called with the name of the event bus and $emit and $on:

EventBus.$on

and

EventBus.$emit('call-modal', { type: 'success' });

How can I make so that instead of calling it with $on and $emit I can call it with this.$root.$emit so that I can use it in every other component? I tried but currently it doesn't work, why?

Here is my App.vue:

<template >
  <div id="app">
    <bankAccount>
    </bankAccount> 
    <div :class="['modal', `modal--type--${modalType}`]" v-show="showModal">
    <slot name="title">e</slot>
    <slot name="description"></slot>
    </div>
  </div>
</template>

<script>
import bankAccount from './components/bankAccount.vue'
import Vue from 'vue'
export const EventBus = new Vue()

export default {
  name: 'app',
  components: {
    bankAccount,
  },
  data() {
    return {
      showModal: false,
      modalType: 'default',
    }
  },
  created() {
    EventBus.$on('call-modal', obj => {
      this.showModal = true
      this.modalType = obj.type
    })
  },
}
</script>

<style>
.modal {
  height: 100px;
  width: 300px;
  border: solid gray 2px;
}

.modal--type--success {
  border-color: green;
}

.modal--type--danger {
  border-color: red;
  width: 100%;
}

.modal--type--warning {
  border-color: yellow;
  width: 100%;
}
</style>

And my component:

<template>
  <div>
   <button class="pleeease-click-me" @click="callModal()">Click me</button>
  </div>
</template>

<script>
import { EventBus } from '../App.vue';


export default {
  name: 'bankAccount',
  data() {
    return {
      showModal: false
    }
  },
   methods: {
    callModal() {
      this.showModal = !this.showModal
     EventBus.$emit('call-modal', { type: 'success' });

    }
  }
}

</script>

<style scoped>

.modal {
  height: 100px;
  width: 300px;

}
</style>

Upvotes: 0

Views: 2333

Answers (3)

Andrew Vasylchuk
Andrew Vasylchuk

Reputation: 4779

To achieve desired result you have to slightly change your code. In your App.vue change these lines of code:

created() {
  this.$root.$on('call-modal', obj => {
    this.showModal = true
    this.modalType = obj.type
  })
},

And then in your component:

callModal() {
  this.showModal = !this.showModal
  this.$root.$emit('call-modal', { type: 'success' })
}

Notice that approach suggested by @Dadboz, is preferable, than you desirable.

Upvotes: 1

Abdelillah Aissani
Abdelillah Aissani

Reputation: 3108

Simply add that to the instance prototype :

// main.js
//import vue from 'vue'

Vue.prototype.$eventHub = new Vue(); 


// new Vue({
//    ...
//  })

now you can use it on any component with :

 this.$eventHub.$emit('call-modal');

Upvotes: 1

Taha Paksu
Taha Paksu

Reputation: 15616

You can create a separate eventbus.js file and include it to all of your components. This way, they'll be using the same eventbus instance. TL;DR: it's been explained here:

https://alligator.io/vuejs/global-event-bus/

Long one:

Create an eventbus.js file with this content:

import Vue from 'vue';
export const EventBus = new Vue();

Then include it:

import { EventBus } from './event-bus.js';

Then use it:

EventBus.$on("event", function(data){
    // do stuff with data
});

with

EventBus.$emit("event", data);

and don't forget to remove the event on destruction:

beforeDestroy {
     EventBus.$off("event");
}

Upvotes: 1

Related Questions