Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

566
Views
VueJs 2.0 emit event from grand child to his grand parent component

It seems that Vue.js 2.0 doesn't emit events from a grand child to his grand parent component.

Vue.component('parent', {
  template: '<div>I am the parent - {{ action }} <child @eventtriggered="performAction"></child></div>',
  data(){
    return {
      action: 'No action'
    }
  },
  methods: {
    performAction() { this.action = 'actionDone' }
  }
})

Vue.component('child', {
  template: '<div>I am the child <grand-child></grand-child></div>'
})

Vue.component('grand-child', {
  template: '<div>I am the grand-child <button @click="doEvent">Do Event</button></div>',
  methods: {
    doEvent() { this.$emit('eventtriggered') }
  }
})

new Vue({
  el: '#app'
})

This JsFiddle solves the issue https://jsfiddle.net/y5dvkqbd/4/ , but by emtting two events:

  • One from grand child to middle component
  • Then emitting again from middle component to grand parent

Adding this middle event seems repetitive and unneccessary. Is there a way to emit directly to grand parent that I am not aware of?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Vue 2.4 introduced a way to easily pass events up the hierarchy using vm.$listeners

From https://vuejs.org/v2/api/#vm-listeners :

Contains parent-scope v-on event listeners (without .native modifiers). This can be passed down to an inner component via v-on="$listeners" - useful when creating transparent wrapper components.

See the snippet below using v-on="$listeners" in the grand-child component in the child template:

Vue.component('parent', {
  template:
    '<div>' +
      '<p>I am the parent. The value is {{displayValue}}.</p>' +
      '<child @toggle-value="toggleValue"></child>' +
    '</div>',
  data() {
    return {
      value: false
    }
  },
  methods: {
    toggleValue() { this.value = !this.value }
  },
  computed: {
    displayValue() {
      return (this.value ? "ON" : "OFF")
    }
  }
})

Vue.component('child', {
  template:
    '<div class="child">' +
      '<p>I am the child. I\'m just a wrapper providing some UI.</p>' +
      '<grand-child v-on="$listeners"></grand-child>' +
    '</div>'
})

Vue.component('grand-child', {
  template:
    '<div class="child">' +
      '<p>I am the grand-child: ' +
        '<button @click="emitToggleEvent">Toggle the value</button>' +
      '</p>' +
    '</div>',
  methods: {
    emitToggleEvent() { this.$emit('toggle-value') }
  }
})

new Vue({
  el: '#app'
})
.child {
  padding: 10px;
  border: 1px solid #ddd;
  background: #f0f0f0
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <parent></parent>
</div>

over 4 years ago · Santiago Trujillo Report

0

NEW ANSWER (Nov-2018 update)

I discovered that we could actually do this by leveraging the $parent property in the grand child component:

this.$parent.$emit("submit", {somekey: somevalue})

Much cleaner and simpler.

over 4 years ago · Santiago Trujillo Report

0

The Vue community generally favors using Vuex to solve this kind of issue. Changes are made to Vuex state and the DOM representation just flows from that, eliminating the need for events in many cases.

Barring that, re-emitting would probably be the next best choice, and lastly you might choose to use an event bus as detailed in the other highly voted answer to this question.

The answer below is my original answer to this question and is not an approach I would take now, having more experience with Vue.


This is a case where I might disagree with Vue's design choice and resort to DOM.

In grand-child,

methods: {
    doEvent() { 
        try {
            this.$el.dispatchEvent(new Event("eventtriggered"));
        } catch (e) {
            // handle IE not supporting Event constructor
            var evt = document.createEvent("Event");
            evt.initEvent("eventtriggered", true, false);
            this.$el.dispatchEvent(evt);
        }
    }
}

and in parent,

mounted(){
    this.$el.addEventListener("eventtriggered", () => this.performAction())
}

Otherwise, yes, you have to re-emit, or use a bus.

Note: I added code in the doEvent method to handle IE; that code could be extracted in a reusable way.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!