Home > Software engineering >  Vue 3 - How to execute a function on binging instance in custom directive
Vue 3 - How to execute a function on binging instance in custom directive

Time:10-23

Im creating a custom directive as follows in main.ts .

let handleOutsideClick: any;
app.directive("closable", {
  mounted: (el, binding, vnode) => {
    handleOutsideClick = (e: any) => {
      e.stopPropagation();

      const payload = binding.value;

      console.log(`instance: ${Object.getOwnPropertyNames(binding.instance)}`);
    };

    document.addEventListener("click", handleOutsideClick);
  },
  unmounted: (el) => {
    document.removeEventListener("click", handleOutsideClick);
  },
});

Inside the event handler i want to make a call to a function on the component that triggered this directive.

With Vue 2 you could do it with vnode.context'myfunction' but this does not seem to work with binding.instance.

How can i call the function using the binding instance?

CodePudding user response:

Passing the function to be called as the binding's value and then calling it seems to work:

if (typeof binding.value === 'function') {
  binding.value()
}

Working example:

const { createApp } = Vue;

const app = createApp({
  setup() {
    return { test: () => console.log('here') }
  }
})

app.component('demo', {
  template: `<div>test</div>`
})

let handleOutsideClick;
app.directive("closable", {
  mounted: (el, binding, vnode) => {
    handleOutsideClick = (e) => {
      e.stopPropagation();

      const payload = binding.value;

      console.log(`instance: ${Object.getOwnPropertyNames(binding.instance)}`);
      if (typeof binding.value === 'function') {
        binding.value()
      }
    };

    document.addEventListener("click", handleOutsideClick);
  },
  beforeUnmount: (el) => {
    document.removeEventListener("click", handleOutsideClick);
  },
});

app.mount('#app')
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
  <demo v-closable="test"></demo>
</div>


Notes:

  • vue internal method names change based on environment. For example, if you remove .prod from the vue link in the example above, you'll get more data out of Object.getOwnPropertyNames(binding.instance).
    If your app's business logic relies on vue internals method naming:
      a) you're doing it wrong™;
      b) it won't work in production
  • if the above is not helpful, please provide more details on your specific use-case via a runnable minimal, reproducible example.
    If you need a multi-file node-like online editor, note codesandbox.io allows importing local projects using their CLI utility.
  • Related