Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js bind to DOM custom event with dots in name (like bootstrap events)

Tags:

vue.js

vuejs2

Using Vue 2.1.10

I can bind to DOM events with v-on directive. For example:

v-on:click

To bind to DOM click. But I can't figure how to bind to an event that has dots in the name. such as "show.bs.modal" from bootstrap.

Currently, I use a workaround binding in the created hook with Regular DOM Methods, but I really would like to use the declarative syntax for that. How can this be achieved? thanks

EDIT: The question is about allowed syntax: how can I do something like:

Vue.component('comp',{
  template:'<div v-on:show.bs.modal="sunrise"></div',
  methods:{
    sunrise:function(e){

     }

   }
})
like image 582
alonisser Avatar asked Oct 18 '22 17:10

alonisser


2 Answers

I was facing the very same problem when working on old projects.

Luckily I found the answer here: vue2 doc

<!-- object syntax (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>

This works on Bootstrap 5.1.1 with Vue 2.16.14:

<div class="modal" v-on="{ 'hide.bs.modal': handleModalClose }">
...
</div>
like image 194
peorthijel Avatar answered Oct 20 '22 15:10

peorthijel


I think dots are not supported in v-on but you could create a custom directive to create an event listener for that event.

Not sure if there is something easier but something like in the demo below or this fiddle should work.

The demo creates a new event with dots in name but that should also work with bootstrap events (not tested). Please let me know if it's not working with bootstrap and I'll have a look.

Unbinding only works if you're using v-if. If you're removing that element with Javascript directly. The event will still be there.

var helloEvent = new Event('demo.event.hello');

document.addEventListener('demo.event.hello', function(e) {
  // this is just for testing event dispatching!
  console.log('main event listener');
}, false);

const bindCustomEvent = {
  getName: function(binding) {
    return binding.arg + '.' +
      Object.keys(binding.modifiers).map(key => key).join('.');
  },
  bind: function(el, binding, vnode) {
    const eventName = bindCustomEvent.getName(binding);

    console.log(el, eventName);
    document.addEventListener(eventName, binding.value);
  },
  unbind: function(el, binding) {
    const eventName = bindCustomEvent.getName(binding);
    console.log('unbinding', eventName);
    document.removeEventListener(eventName, binding.value);
  }
};

Vue.directive('bindCustomEvent', bindCustomEvent);

new Vue({
  el: '#app',
  data() {
    return {
      enabled: true,
      eventMsg: ''
    };
  },
  methods: {
    sunrise: function(e) {
      console.log('received event');
      this.eventMsg = 'received event';
    },
    testEvent: function() {
      document.dispatchEvent(helloEvent);
    },
    toggle: function() {
      console.log('toggle', this.enabled);
      this.enabled = !this.enabled;

      if (!this.enabled) {
        this.eventMsg = '';
      }
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<div id="app">
  <div v-bind-custom-event:demo.event.hello="sunrise" v-if="enabled">
    Hello, {{eventMsg}}
  </div>

  <!--
  The following markup is not working
  <div v-on="demo.event.hello:sunrise" v-if="enabled">
    Hello, {{eventMsg}}
  </div>-->
  <button @click="testEvent()">
    Change
  </button>
  <button @click="toggle">
    <span v-if="enabled">disable custom event</span>
    <span v-else>enable custom event</span>
  </button>
</div>
like image 20
AWolf Avatar answered Oct 20 '22 15:10

AWolf