November 4, 2020
Vue Custom Directives – How to detect click outside
One of useful features of vue js that some of other front end frameworks lack are directives, with directives you can add functionalities to the template such as conditions, loops, data binding, etc.
While Vue has a handful of directives by default, you can create your own directives too. In this post I will create a custom directive named v-clickoutside to call a method whenever the user clicks outside the element that has this directive.
How to create a custom Vue directive
In order to register a global directive, you have to use the Vue.directive method, this function accepts two arguments, the first argument is the name of the directive in string and without v- prefix and the second argument is an object that contains element’s life cycle hooks which occur in this order:
bind: called when the directive is attached to the element.
inserted: called when the element is inserted into the parent DOM
update: called when the element is updated (but not it’s children)
componentUpdated: called when the component and It’s children have been updated
unbind: — called when the directive is removed
These hooks have these arguments:
el: the element that has the directive
binding: an object that contains the arguments that are passed to the hooks
vnode — virtual DOM node of the element
Click Outside directive
so which one of these hooks do we need for our click outside directive? we need to register the click and toch events when the element is inserted into DOM and unregister these events when the element is destroyed so we’ll use inserted and unbind hooks:
Vue.directive('clickoutside', {
inserted: (el, binding, vnode) => {
// assign event to the element
el.clickOutsideEvent = function (event) {
// here we check if the click event is outside the element and it's children
if (!(el == event.target || el.contains(event.target))) {
// if clicked outside, call the provided method
vnode.context[binding.expression](event)
}
}
// register click and touch events
document.body.addEventListener('click', el.clickOutsideEvent)
document.body.addEventListener('touchstart', el.clickOutsideEvent)
},
unbind: function (el) {
// unregister click and touch events before the element is unmounted
document.body.removeEventListener('click', el.clickOutsideEvent)
document.body.removeEventListener('touchstart', el.clickOutsideEvent)
},
stopProp(event) {
event.stopPropagation()
},
})
Usage
so how do we use this directive that we just created? for example we want to hide a div element when the user clicks outside that element:
<template>
<div v-show="show" v-clickoutside="hide" class="hide-on-clickoutside">
hide me when clicked outside
</div>
</template>
<script>
export default {
data(){
return{
show: true
}
},
methods: {
hide(){
this.show = false
}
},
};
</script>
<style scoped></style>