Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js 2 - How to $emit event from one application/instance Vue to an other?

Tags:

vue.js

vuejs2

I use webpack with Single File Component.

I have 1 instance of Vue in my menu header to show a Cart Shopping dropdown :

import Vue from 'vue';
import App from './AppShoppingCart.vue';

new Vue({
    el: '#shoppingCartApp',
    template: '<App/>',
    components: {App}
});

I have an other Vue instance in the same page (the catalog with products) :

import Vue from 'vue';
import App from './AppCatalog.vue';

new Vue({
    el: '#catalogApp',
    template: '<App/>',
    components: {App}
});

I want to $emit an event from one instance to the other : when Catalog change, I want to call a function in ShoppingCart.

I test eventHub :

import Vue from 'vue';

var eventHub = new Vue();
export default eventHub; 

So I import event on each instance :

import eventHub from './events/eventHub';

In Catalog :

eventHub.$emit( "actproductslist-changed" );

In ShoppingCart :

eventHub.$on('actproductslist-changed', function(){ alert('AppShoppingCart') } );

But this won't works. It only works if the $on and $emit are in the same instance of Vue.

I think webpack create 2 modules and I can't share variables between my 2 instances.

Any one have an idea to have global variable with multiple instance with webpack ?

like image 422
Happyriri Avatar asked Mar 16 '17 15:03

Happyriri


1 Answers

This setup works, where main.js is your entry point.

bus.js

import Vue from "vue"

const bus = new Vue();
export default bus;

main.js

import Vue from 'vue'
import App from './App.vue'
import App2 from './App2.vue'

new Vue({
  el: '#app',
  render: h => h(App)
})

new Vue({
  el:"#app2",
  render: h => h(App2)
})

App.vue

<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script>
  import Vue from "vue"
  import bus from "./bus"

  export default {
    methods:{
      sendMessage(){
        bus.$emit("testing")
      }
    }    
  }
</script>

App2.vue

<template></template>

<script>
  import Vue from "vue"
  import bus from "./bus"

  export default {
    mounted(){
        bus.$on("testing", ()=> alert("message received"));
    }
  }
</script>

Post comment edit

To communicate across entry points, you can expose the bus Vue on the window.

webpack.config.js

  entry: {
    "main": './src/main.js', 
    "main2": './src/main2.js'
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: '[name].js'
  },

bus.js

import Vue from "vue"

window.bus = new Vue();

main.js

import Vue from 'vue'
import App from './App.vue'

new Vue({
  el: '#app',
  render: h => h(App)
})

main2.js

import Vue from 'vue'
import App2 from './App2.vue'
import bus from "./bus"

new Vue({
  el:"#app2",
  render: h => h(App2)
})

App.vue

<template>
  <button @click="sendMessage">Send Message</button>
</template>

<script>
  import Vue from "vue"

  export default {
    methods:{
      sendMessage(){
        if (bus)
          bus.$emit("testing")
      }
    }    
  }
</script>

App2.vue

<template></template>

<script>
  import Vue from "vue"

  export default {
    mounted(){
        bus.$on("testing", ()=> alert("message received"));
    }
  }
</script>

Note here that since bus is only imported in main2.js, you need to guard the use of it in App.vue for those cases where it might not exist (because it is only imported in main2.js).

like image 183
Bert Avatar answered Nov 15 '22 10:11

Bert