1

I have create a new Vue instance and assigned it to my window, which should give me access to it throughout all components. This should give me access to events emitted anywhere within my application.

However for some reason this is not the case, can someone advise me?

app.js

window.Vue = require('vue');
window.events = new Vue();
window.app = new Vue({
    el: '#app',
    methods: {
        emit: function (name, params) {
            window.events.$emit(name, params);
        }
    }
});

I have created a emit method within my app for my components to use, as simply calling v-on:change="window.events.$emit('makeChanged', $event)" was not working, I was getting the error that window is not defined.

I'm listening for any emitted events from the emit within my component as follows:

window.events.$on('makeChanged', function(evt) {});

Edit:

Still can't get this working...

app.js

Vue.component('models-select', require('./components/results-text/ModelsSelect.vue'));

window.app = new Vue({
    el: '#app',
    methods: {
        emit(name, ...params) {
            this.$root.$emit(name, ...params);
        },
    ...

ModelsSelect.vue

export default {
        props: [ 'endpoint', 'makeId', 'modelId', 'typeId'],
        mounted() {

            this.$root.$on('make-changed', function(evt) {
                console.log(evt);
            });

Within one of my views (add.blade.php)

<select name="make" id="makes" v-on:change="emit('make-changed', $event)" tabindex="2" class="{{ old('make') ? ' is-changed' : '' }}">
Martyn Ball
  • 4,679
  • 8
  • 56
  • 126
  • Can you try changing your emit to `this.$root.$emit` and your listener to `this.$root.$on`? – Lewis Apr 23 '19 at 15:44
  • @Lewis no luck, if I add a created method to the instance of Vue, and listen for the event there it works, however the component is not picking the event up. – Martyn Ball Apr 23 '19 at 15:51
  • Odd. I know it's not an answer to your question but it seems to be recommended to use an [Event Bus](https://medium.com/easyread/vue-as-event-bus-life-is-happier-7a04fe5231e1) for stuff like this. The [VueJS Docs](https://stackoverflow.com/questions/50181858/this-root-emit-not-working-in-vue) seem to consider this an edge case. Mentioned in a comment on that link. – Lewis Apr 23 '19 at 15:57
  • Why not use [Vuex](https://vuex.vuejs.org/) for this... Kick of an action vs emitting events, and listen for those events in your components via watchers.. – Matt Oestreich Apr 23 '19 at 16:28

2 Answers2

6

You can emit and listen events with $root element.

methods: {
    emit(name, ...args) {
        this.$root.$emit(name, ...args)
    }
}

In components:

mounted() {
    this.$root.$on('event-name', this.handleEvent)
},
beforeDestroy() {
    this.$root.$off('event-name', this.handleEvent)
},
methods: {
    handleEvent() {
        // handle event (with optional args)
    }
}
Daniel
  • 2,621
  • 2
  • 18
  • 34
1

You can't use window in v-on::

API docs:

The expression can be a method name, an inline statement, or omitted if there are modifiers present.

To do what you want to do you should move access to window.events to the method:

<some-element v-on:change="globalEmit('makeChanged', $event)" />
{
  methods: {
    globalEmit(name, ...params) {
      window.events.$emit(name, ...params);
    }
  }
}

Then, you can move this globalEmit method to the global mixin, rename it to $gemit (for example) and use it everywhere like this:

<some-element v-on:change="$gemit('makeChanged', $event)" />
tony19
  • 125,647
  • 18
  • 229
  • 307
Styx
  • 9,863
  • 8
  • 43
  • 53