dgeare
dgeare

Reputation: 2658

Why does $emit not work in my vue component

I've been banging my head against this problem for hours. I can't see a problem and from what I can tell I am following the documentation here: https://v2.vuejs.org/v2/guide/components-custom-events.html

code below

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="wrap">
  <test-listen>
    <test-emit></test-emit>
  </test-listen>
</div>
<script>
Vue.component('test-listen', {
  data: function(){
    return {};
  },
  methods: {
    customHandler : function(e){
      console.log(e);
      console.log("works");
    }
  },
  template: `
    <div class='test_listen' v-on:custom="customHandler">
      <slot></slot>
    </div>
  `
});

Vue.component('test-emit',{
  data: function(){
    return {};
  },
  methods: {
    clickHandler : function(){
      this.$emit('custom');
    }
  },
  template : `
    <div class='test_emit' v-on:click="clickHandler">
      test
    </div>
  `
});

new Vue({
  el:"#wrap"
});
</script>
<style>
.test_listen{
  display:block;
  padding:20px;
  border:1px solid #000;
}
.test_emit{
  display:block;
  width:100px;
  height:100px;
  background-color:#f0f;
  color:#fff;
  font-weight:700;
  font-size:20px;
}
</style>

But the listeners are definitely bound to the element, because if I dispatch a vanillaJS CustomEvent it triggers the console log just fine. What am I missing?

Upvotes: 9

Views: 62625

Answers (3)

Majed Fayazi
Majed Fayazi

Reputation: 553

I see only one mistake here. You should add v-on to the child component. When you $emit('custom') from inside it will call "customHandler" on the parent component.

Working jsfiddle

<test-listen>
    <test-emit v-on:custom="customHandler"></test-emit>
</test-listen>

Upvotes: 13

Hardik Satasiya
Hardik Satasiya

Reputation: 9693

There are 2 things wrong here.

  1. Vue events can be bound to components only I guess (talking vue events here)
  2. Slots are not good with events. (Source - Evan You, Vue author)

If you really want to pass data here and there without restriction better to use Global Event Bus Approach

Working example of your code with some minor correction.

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="wrap">
  <test-listen>
  </test-listen>
</div>
<script>
Vue.component('test-listen', {
  data: function(){
    return {};
  },
  methods: {
    customHandler : function(e){
      console.log(e);
      console.log("works");
    }
  },
  template: `
    <div class='test_listen' >
      <test-emit v-on:custom="customHandler"></test-emit>
    </div>
  `
});

Vue.component('test-emit',{
  data: function(){
    return {};
  },
  methods: {
    clickHandler : function(e){
      // e => event : didnt pass here as console will stuck so
      this.$emit('custom', 'somedata');
    }
  },
  template : `
    <div class='test_emit' v-on:click="clickHandler">
      test
    </div>
  `
});

new Vue({
  el:"#wrap"
});
</script>
<style>
.test_listen{
  display:block;
  padding:20px;
  border:1px solid #000;
}
.test_emit{
  display:block;
  width:100px;
  height:100px;
  background-color:#f0f;
  color:#fff;
  font-weight:700;
  font-size:20px;
}
</style>

Upvotes: 3

Roland
Roland

Reputation: 27729

With this.$emit() is a way to say to the parent component that hey i created an event and now you can listen on this event

You are doing well but you don't listen in parent component the event emitted by child. I made it to work.Click here to see it in action

So in order to make your code to work,In test-listen component,use as child the test-emit component.

Then inside the div #wrap use the test-listen component

Your problem was that you did't listen to the event in parent component.

Upvotes: 2

Related Questions