1

I've seen this question and tried both the this.$parent and the this.$root alternatives, to no avail. The situation is as follows.

App.vue

<template>
    <div id="app">
        <global-notifications/>
        <router-view></router-view>
    </div>
</template>

<script>
import GlobalNotifications from "./components/GlobalNotifications.vue"

export default {
    name: "app",
    components: {
        GlobalNotifications
    }
};
</script>

GlobalNotifications.vue

<template>
    <div>
        <p>Notifications:</p>
        <p v-for="n in notifications" :key="n.id">{{ n }}</p>
        <b-button @click="internalEmitter">Internal notification!</b-button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            notifications: []
        }
    },
    methods: {
        appendNotification(n) {
            this.notifications = [...this.notifications, n]
        },
        internalEmitter() {
            let message = { id: `${Math.floor(Math.random()*1000000)}`, message: 'From the inside!' }
            this.$emit('global-notification', message)
        }
    },
    mounted() {
        this.$on('global-notification', this.appendNotification)
    },
    beforeDestroy() {
        this.$off('global-notification', this.appendNotification)
    }
}
</script>

Dashboard.vue

Gets loaded through the router. Yes, I tried loading it directly from App.vue.

<template>
    <b-button @click="emitTheThing">External notification!</b-button>
</template>

<script>
export default {
    methods: {
        emitTheThing() {
            let message = { id: `${Math.floor(Math.random()*1000000)}`, message: 'From the outside!' }
            this.$emit('global-notification', message)
        }
    }
}
</script>

When I click on the Internal notification! button, I get events fired and caught, and everything works as expected. However, when I click on the External notification! button, the only evidence of events flying around that I can see is in the Vue Dev Tools, where I see events being emitted.

As I said, I tried emitting on $parent and even on $root, but I only see the events in the dev tools, being emitted on <App> and <Root>, respectively. However, the GlobalNotification child does not seem to catch them.

What am I missing?

2
  • 2
    Uses event bus should be one option. check Vuejs setting up event bus Commented Jun 14, 2018 at 22:07
  • I thought about that but it sounded like an overkill to my ears. I will go down that route if there really are no other options, though. Commented Jun 14, 2018 at 22:10

1 Answer 1

3

The problem is the <global-notifications> component listens for events on itself, while you're emitting the event on the root component. Note that emitting the event on a root component does not broadcast the event to the root's child components (as you've observed with Vue DevTools).

A quick fix in your case is to use $root.$on() so that it sets up the listener on the root component:

mounted() {
    // this.$on('global-notification', this.appendNotification)
    this.$root.$on('global-notification', this.appendNotification)
},

Then, you can use $root.$emit() from any component in any heirarchy to emit an event to the root component.

demo

Sign up to request clarification or add additional context in comments.

2 Comments

@Sphinx Thanks for the heads up on the demo. Fixed now. Regarding the second comment, the OP states I tried emitting on $parent and even on $root.
Hey. I hadn't thought of listening on $root, that's a good point, even if terrifying from an encapsulation point of view :) both this and the bus are good alternatives in such a simple case. I'll give it a thought and decide if I can live with this quick and dirty solution or if I need a more flexible approach!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.