Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vue.js firing $emit not received by $on

Vue.component('rating-edit', {
    template:`
    <form>
      <input v-model="rating.title" type="text">
      <textarea v-model="rating.remark">{{rating.remark}}</textarea>
      <button type="button"
        @click="submit">
        Save
      </button>
    </form>`,
    props:['rating'],
    methods: {
      submit: function submit () {
        let rating = this.rating;
        this.$emit('submit', rating);
        console.log('submit was emitted');
      }
    }
  });

const aRating = {
    title: 'title',
    remark: 'remark'
  };

let vueApp = new Vue({
    el: '#rating-edit-container',
    data: {
      rating: aRating
    }
  });

vueApp.$on('submit', function(rating) {
  console.log('vue on submit', rating);
});
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="rating-edit-container">
  <rating-edit :rating="rating"></rating-edit>
</div>

In a legacy frontend code I'd like implement a vue based componentized form and have it return the data on submit.

This is the component code. Please note the submit function firing this.$emit('submit', rating);

let result = {
  props:['rating'],
  methods: {
    submit: function submit () {
      let rating = this.rating;
      this.$emit('submit', rating);
      console.log('submit fired');
    }
  }
};

export default result;

And now in the legacy code, I am waiting for the events:

import Vue from 'vue';
import ratingEditVue from './rating-edit.vue';


Vue.component('rating-edit', ratingEditVue);

const aRating = {
  title: 'title',
  remark: 'remark'
};

let vueApp = new Vue({
  el: '#rating-edit-container',
  data: {
    rating: aRating
  }
});

vueApp.$on('submit', function(rating) {
  console.log('vue on submit', rating);
});

As far as I understand the Vue events this should work. But $on('submit', handlerFunction) just never gets called.

Addendum:

I've fiddled the example. I apologize for not having done this in the first place.

like image 978
LongHike Avatar asked Jul 18 '17 11:07

LongHike


2 Answers

The issue is that you are emitting along the same scope depth of your rating-edit component.

If you instead emit to the parent with this.$parent.$emit, the event will be received by the parent. Note, if you need to do this in multiple places or at multiple depths, you want to use an event bus instead.

Vue.component('rating-edit', {
    template:`
    <form>
      <input v-model="rating.title" type="text">
      <textarea v-model="rating.remark">{{rating.remark}}</textarea>
      <button type="button"
        @click="submit">
        Save
      </button>
    </form>`,
    props:['rating'],
    methods: {
      submit: function submit () {
        let rating = this.rating;
        this.$parent.$emit('submit', rating);
        console.log('submit was emitted');
      }
    }
  });

const aRating = {
    title: 'title',
    remark: 'remark'
  };

let vueApp = new Vue({
    el: '#rating-edit-container',
    data: {
      rating: aRating
    }
  });

vueApp.$on('submit', function(rating) {
  console.log('vue on submit', rating);
});
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="rating-edit-container">
  <rating-edit :rating="rating"></rating-edit>
</div>
like image 179
David L Avatar answered Oct 20 '22 00:10

David L


vueApp.$on('submit', function(rating) {
  console.log('vue on submit', rating);
});

Your handler here will only be executed in response to submit events emitted from vueApp directly (i.e. vueApp.$emit('submit')), which I don't think is happening in your code (which isn't fully provided).

Vue events do not bubble.

Suppose your #rating-edit-container template is something like this:

<template id="rating-edit-container">
  <div>
    <rating-edit @submit="onRatingSubmit"></rating-edit>
  </div>
</template>

Then you should have your handler (onRatingSubmit) declared in the methods of your component like this:

let vueApp = new Vue({
  el: '#rating-edit-container',
  methods: {
    onRatingSubmit(rating) {
      console.log('rating submit', rating);
    },
  },
});

EDIT

You still have the same issue as what I described. I modified your snippet by removing the emission on $parent instead of this and registering the listener on the <rating-edit> element in the template.

Vue.component('rating-edit', {
    template:`
    <form>
      <input v-model="rating.title" type="text">
      <textarea v-model="rating.remark">{{rating.remark}}</textarea>
      <button type="button"
        @click="submit">
        Save
      </button>
    </form>`,
    props:['rating'],
    methods: {
      submit: function submit () {
        let rating = this.rating;
        this.$emit('submit', rating);
        console.log('submit was emitted');
      }
    }
  });

const aRating = {
    title: 'title',
    remark: 'remark'
  };

let vueApp = new Vue({
    el: '#rating-edit-container',
    data: {
      rating: aRating
    },
    methods: {
      onSubmit(rating) {
        console.log('vue on submit', rating);
      },
    },
  });
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="rating-edit-container">
  <rating-edit :rating="rating" @submit="onSubmit"></rating-edit>
</div>
like image 30
Decade Moon Avatar answered Oct 19 '22 23:10

Decade Moon