11

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

2
  • where is the problem in your code ? Commented Mar 22, 2016 at 14:07
  • @John ping method (where alert('Vue ping')) doesn't get called Commented Mar 22, 2016 at 14:52

4 Answers 4

9

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() {....} }

Sign up to request clarification or add additional context in comments.

5 Comments

It doesn't work. "This event system is independent from the native DOM events and works differently." I think it for communication between Vue components, rather than between DOM nodes.
It does not work how? Since you are using Vue.js, I was under the impression you wanted to communicate beweteen components?` Why would you want to communicate between DOM nodes in Vue - since the goal of Vue is to decouple the business logic from the DOM? Maybe we could help you translate your usecase into "the Vue way" if you provide additional information about it.
I would be very thankful if you fix source code I provided. The question was: how to attach a custom event handler in Vue so that it may intercept events emitted by jQuery.trigger.
jQuery emits DOM events. Vue does use its own event system. So the answer is: you cannnot use v-on for DOM events. You will have to use jQuery.on() with callbacks, set up in ready() like you already demonstrated. Depending on the usecase, this could be extracted into a custom directive (see docs).
So how then can I listen to svg events that are in my embedded svg with internal vue custom event system?
3

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.

Comments

2

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

2 Comments

This is meaningless. I use jQuery(event.target).trigger('ping') because I don't know who will handle this event. I need to inform a parent that something happened with its descendant.
0

I came across the same problem and the solution is pretty simple if you're using v-autocomplete from Vuetify.

What I did

  1. Add a key in data, I'm calling it searchText
  2. Bind that property with v-model:search
  3. Add an event handler called @update:modelValue
  4. Declear a method and add that method on @update:modelValue="emptySearchText"

Here is an example.

<v-autocomplete
  label="Your Label"
  :items="items"
  v-model="selected"
  v-model:search="searchText"
  @update:modelValue="emptySearchText"
  multiple>
</v-autocomplete>

data: () => ({
  searchText: null
})


methods: {
  emptySearchText () {
    this.searchText = '';
  }
}

Check this out for more information. https://vuetifyjs.com/en/api/v-autocomplete/#events-update:modelValue

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.