VueJS Custom directive + emit event
Asked Answered
H

1

10

I need to $emit an event from a custom directive. Is it possible?

directive.js:

vnode.context.$emit("myEvent") // nothing append
vnode.child.$emit("myEvent")   // error
vnode.parent.$emit("myEvent")  // error

component.vue:

<div v-directive.modifier="binding" @myEvent="method()"></div>

Do you know if it's possible or if there is any trick?

Thanks

Harassed answered 13/3, 2018 at 19:29 Comment(2)
When do you want to trigger the event?Dehumanize
I listen in a component (component.vue). component is in page. component have directive (directive.js).Harassed
D
16

A <div> is not a VueComponent, which means it doesn't have an $emit method.

So to make your Vue custom directive emit an event, you will have to do some checking first:

  • If the directive was used in a Vue custom component, then call $emit() of that component's instance
  • If the directive was used in a regular DOM element (...because there's no $emit()...), then dispatch a native DOM event using .dispatchEvent.

Luckily, Vue's v-on listeners respond to native custom events.

That should be all. Demo implementation below.

Vue.component('my-comp', {
  template: `<input value="click me and check the console" size="40">`
});

Vue.directive('my-directive', {
  bind: function (el, binding, vnode) {

    // say you want to execute your logic when the element is clicked
    el.addEventListener('click', function (e) {
    
      var eventName = 'my-event';
      var eventData = {myData: 'stuff - ' + binding.expression}
      if (vnode.componentInstance) {
      	vnode.componentInstance.$emit(eventName, {detail: eventData}); // use {detail:} to be uniform
      } else {
      	vnode.elm.dispatchEvent(new CustomEvent(eventName, {detail: eventData}));
      }

    })
  }
})

new Vue({
  el: '#app',
  methods: {
    handleStuff(e) { console.log('my-event received', e.detail); }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>

<div id="app">
  <div v-my-directive.modifier="'native element'" @my-event="handleStuff">CLICK ME AND CHECK THE CONSOLE</div>
  <hr>
  <my-comp v-my-directive.modifier="'custom component'" @my-event="handleStuff"></my-comp>
</div>
Dehumanize answered 13/3, 2018 at 21:27 Comment(5)
Thank you. but where is it write ? vuejs.org/v2/api/#vm-emit or vuejs.org/v2/guide/custom-directive.html. Plus, Do i need to stop propagation in div or component that use this directive with a prevent or stop ?Harassed
What do you mean by "where is write"? There's a demo above. No need to stop propagation, unless you have some requirement to specifically do it. If you don't know it is because you don't have it.Dehumanize
Sorry, bad english :D. I have not seen anything in the documentation about "vnode.componentInstance" or the mechanism you describe to me. Your demonstration is very good thank you.Harassed
Ah, yeah, the componentInstance is "documented" in the interface: github.com/vuejs/vue/blob/dev/flow/vnode.js#L14 it is part of it. It is not an internal property because internal properties begin with a _ (and don't appear in the interface). It is the same as the well-known vnode.context, guess there aren't many tutorials using it because it is an advanced feature of Vue.Dehumanize
Ah OK. Thanks again. Do you know where I can find information on advanced features? I have needs vuex, real time store share by multi users ... Moreover, I just posted a question on vuex here: https://mcmap.net/q/1163308/-vuejs-vuex-mapactionsHarassed

© 2022 - 2024 — McMap. All rights reserved.