Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listen to custom event in Vue.js

Vue.js works great with browser events such as click or mousedown. But not work at all with custom events. Here is the code:

HTML:

<div id="app" style="display: none" v-show="true">
    <div v-el:ping v-on:ping="ping">
        <div>
            <button v-on:click="click">Click</button>
        </div>
    </div>
</div>

JavaScript:

new Vue({
    el: '#app',
    data: {
    },
    methods: {
        ping: function (event) {
            console.log('Vue ping', event);
            alert('Vue ping');
        },
        click: function (event) {
            jQuery(event.target).trigger('ping');
        }
    },
    ready: function () {
        console.log(this.$els);
        jQuery(this.$els.ping).on('ping', function (event) {
            console.log('jQuery ping', event);
            alert('jQuery ping');
        });
    }
});

I expect alert with Vue ping and jQuery ping. But only the later pops up.

CodePen

like image 235
vbarbarosh Avatar asked Mar 22 '16 14:03

vbarbarosh


3 Answers

Here it is in vanilla JS:

HTML:

<div id="app">
  <div v-el:ping>
    <div>
      <button v-on:click="click">Click</button>
    </div>
  </div>
</div>

JS:

(function() {

  new Vue({
    el: '#app',
    data: {
      event: null
    },
    methods: {
      ping: function(event) {
        alert('Vue ping');
      },
      click: function(event) {
        this.$els.ping.dispatchEvent(this.event);
      }
    },
    ready: function() {
      this.event = document.createEvent("HTMLEvents");
      this.event.initEvent("ping", true, true);
      this.$els.ping.addEventListener('ping', this.ping);
    }
  });

})();

pen: http://codepen.io/anon/pen/wGdvaV?editors=1010#0

like image 103
Jeff Avatar answered Oct 01 '22 00:10

Jeff


You should avoid to mix a dom events and vue-components related ones because it's a different layers of abstraction.

Anyway, if you still want to do that, I think you need to cache this.el inside a vue-component instance or take it via computed-property like this

{
    computed : {
        jqueryEl(){ return $(this.el) }
    }
}

And then trigger a custom jQuery events by this.jqueryEl.trigger('ping').

Sure to properly take care of keep the element's bindings up to date! For example you can bind jQuery events dynamically (and also unbind on component destroy!) like this:

 ready : function(){
    jQuery('body').on('ping.namespace', '[data-jquery="ping"]', function(){ ... })
 },
 destroy : function(){
      jQuery('body').off('ping.namespace')
 }

And don't forget to add attribute [data-jquery="ping"] to an element which you would like to response a ping event.

Hope this information helps you to achieve the expected result.

like image 26
Panama Prophet Avatar answered Sep 30 '22 22:09

Panama Prophet


Vue has its own internal system for custom events, which you should use instead of jQuery / native DOM events:

click: function (event) {
  // jQuery(event.target).trigger('ping');
  
  this.$dispatch('ping', event.target) // send event up the parent chain, optionally send along a reference to the element.
  
  // or:
  this.$emit('ping') // trigger event on the current instance
}

Edit: $dispatch is for parent-child communication, You seem to want to trigger a custom event from within the same comonent. In that case, you could instead simply call a method.

If you still want to listen to a custom event inside the same component, you:

  1. want to use $emit

  2. cannot use v-on:custom-event-name in the template (that's only to be used on components). Rather, add the event method to the events::

    events: { ping: function() {....} }

like image 36
Linus Borg Avatar answered Sep 30 '22 22:09

Linus Borg