Morpheu5
Morpheu5

Reputation: 2801

VueJS emitted event not getting caught by other components in the same hierarchy

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?

Upvotes: 1

Views: 2403

Answers (1)

tony19
tony19

Reputation: 138696

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

Upvotes: 3

Related Questions