Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

576
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda