2

I am trying to create a custom directive using this example: https://stackoverflow.com/a/42389266/5470563

main.ts file:

import Vue from 'vue';
import HeaderNav from './components/HeaderNav.vue'

Vue.directive('click-outside', {
    bind: function (el, binding, vnode) {
        el.clickOutsideEvent = function (event) {
            // here I check that click was outside the el and his childrens
            if (!(el == event.target || el.contains(event.target))) {
                // and if it did, call method provided in attribute value
                vnode.context[binding.expression](event);
            }
        };
        document.body.addEventListener('click', el.clickOutsideEvent)
    },
    unbind: function (el) {
        document.body.removeEventListener('click', el.clickOutsideEvent)
    },
});

new Vue({
    el: '#app',
        components: {
            HeaderNav
        }
});

And I get a compile error:

Property 'clickOutsideEvent' does not exist on type 'HTMLElement'.

How do I fix it? Or is there any better solution to bind events on outside element click?

2 Answers 2

2

You have 2 options

cast el param in bind, unbind function to any.

bind: function (el: any, binding, vnode) {
unbind: function (el: any) {

extend HTMLElement interface.

You can place it before directive declaration.

interface HTMLElement {
  clickOutsideEvent: () => void;
}
Sign up to request clarification or add additional context in comments.

2 Comments

Compile runs fine now, but I get JS error after clicking anywhere: Uncaught TypeError: vnode.context[binding.expression] is not a function at HTMLBodyElement.el.clickOutsideEvent
Oh it's because I had no function defined as attribute for v-click-outside custom directive. Thank you!
1

Here is an implementation I currently use, hope it helps:

export default {
  bind: function(el, binding, vNode) {
    // Provided expression must evaluate to a function.
    if (typeof binding.value !== "function") {
      const compName = vNode.context.name;
      let warn = `[Vue-click-outside:] provided expression '${binding.expression}' is not a function, but has to be`;
      if (compName) {
        warn += `Found in component '${compName}'`;
      }

      console.warn(warn);
    }
    // Define Handler and cache it on the element
    const bubble = binding.modifiers.bubble;
    const handler = e => {
      if (bubble || (!el.contains(e.target) && el !== e.target)) {
        binding.value(e);
      }
    };
    el.__vueClickOutside__ = handler;
    // add Event Listeners
    document.addEventListener("mousedown", handler);
  },
  unbind: function(el, binding) {
    // Remove Event Listeners
    document.removeEventListener("mousedown", el.__vueClickOutside__);
    el.__vueClickOutside__ = null;
  }
};

Then register the directive in your main file

// Directives
Vue.directive("click-outside", ClickOutside);

2 Comments

OP had typescript error, his javascript code looks fine.
Just suggesting a solution I previously used in case this one didn't work out.

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.