Lou Lou - 1 month ago 125
Javascript Question

$emit an event from child to parent in vue.js, es6 syntax

I'm pretty new to Vue.js, and I use es6 syntax with vue-class-component. I'm having a problem while trying to emit an event from a child to it's parent. I followed the logic of the default Vue.js syntax but can't get it over with. Here are some more informations :

export default class HorizontalNavigation {

handleClick (e) {
e.preventDefault();
// console.log(e.target.dataset.section);
this.$emit('ChangeView', e.target.dataset.section);
}

render (h) {
return (
<div class={ style.horizontalNavigation } >
<div class='sections-wrapper'>
<div class={ style.sections }>
<ol>
<li><a on-click={ this.handleClick } href='#1' data-section='1' class='selected'>We are</a></li>
<li><a on-click={ this.handleClick } href='#2' data-section='2'>Services</a></li>
<li><a on-click={ this.handleClick } href='#3' data-section='3'>Cases</a></li>
<li><a on-click={ this.handleClick } href='#4' data-section='4'>Studio</a></li>
<li><a on-click={ this.handleClick } href='#5' data-section='5'>Career</a></li>
<li><a on-click={ this.handleClick } href='#6' data-section='6'>Contact</a></li>
</ol>

<span class='filling-line' aria-hidden='true'></span>
</div>
</div>
</div>
);
}
}


Here is the child. I attached a click on every li to pass it to the parent. And here is the parent.

export default class ViewsContainer {

ChangeView (data) {
console.log(data);
}

render (h) {
return (
<div class={ style.restrictOverflow } >
<HorizontalNavigation />
<main class={ style.viewsContainer } on-ChangeView={ this.ChangeView } >
<SingleView dataSection='weare' id='1' class='selected' />
<SingleView dataSection='services' id='2' />
<SingleView dataSection='cases' id='3' />
<SingleView dataSection='studio' id='4' />
<SingleView dataSection='career' id='5' />
<SingleView dataSection='contact' id='6' />
</main>
</div>
);
}
}


Following the vue.js syntax, I should be able to listen to the childs event from the parent by passing the event to the element like having an @ChangeView but nothing's travelling through component but props...
Any thougts on that ? Thank you !

Answer

You need to $emit on the view model you want to receive your $emit, use a bus or use https://vuex.vuejs.org/en/intro.html.

The easiest way, is to simply $emit directly to the parent:

 this.$parent.$emit('ChangeView', e.target.dataset.section);

This is OK, but if you have a long chain of components you need to $emit to each $parent in the chain.

Another option is to use as Vue vm as a bus by placing the bus in your main component and emiting onto it:

var bus = new Vue({});
var vm = new Vue({
  methods: {
     changeView() {
        bus.$emit('ChangeView', e.target.dataset.section);
     }
  }
);

It is also possible to emit to $root but this isn't recommended. However, if your app does get quite complex you may want to consider using Vues own state management system, vuex, instead.

You can listen for the $emit in the viewmodel using $on and listening for the specific event:

var vm = new Vue({
  created() {
     this.$on('ChangeView', section => {
        console.log(section);
      });
  }
);

This would also be similar is you were using the bus, but you would just reference the bus instead:

bus.$on('ChangeView, ...)

And you may also use it directly in your html using `v-on:

<div v-on:ChangeView="doSomething"></div>