menu

Questions & Answers

How do you handle click-outside of element properly in vuejs?

Is there any proper solution for handling click-outside of elements?

there are general solutions out there, like Handling clicks outside an element without jquery :

window.onload = function() {

    // For clicks inside the element
    document.getElementById('myElement').onclick = function(e) {
            // Make sure the event doesn't bubble from your element
        if (e) { e.stopPropagation(); } 
        else { window.event.cancelBubble = true; }
            // Place the code for this element here
        alert('this was a click inside');
    };

    // For clicks elsewhere on the page
    document.onclick = function() {
        alert('this was a click outside');
    };
};

But the problem is almost all projects have multiple and different popups in different components which i should handle their click-outsides.

how should i handle click-outisde without using a global window.on?(I think it is not possible to put all components outside-case handler in window.on )

Comments:
2023-01-19 23:20:11
2023-01-19 23:20:11
Something for Vue 3 + Composition API - (from fantastic "utility" library VueUse)
Answers(3) :

After struggling with this and searching about this, i found how to solve this problem using vuejs directive without bleeding:

1. using libraries:

v-click-outside is a good one,

https://www.npmjs.com/package/v-click-outside

2. without a library:

```
//main.js
import '@/directives';
......

// directives.js
import Vue from "vue";
Vue.directive('click-outside', {
  bind: function (element, binding, vnode) {
    element.clickOutsideEvent = function (event) {  //  check that click was outside the el and his children
      if (!(element === event.target || element.contains(event.target))) { // and if it did, call method provided in attribute value
        vnode.context[binding.expression](event);
        // binding.value(); run the arg
      }
    };
    document.body.addEventListener('click', element.clickOutsideEvent)
  },
  unbind: function (element) {
    document.body.removeEventListener('click', element.clickOutsideEvent)
  }
});
```

use it every-where you want with v-click-outside directive like below:

//header.vue
 <div class="profileQuickAction col-lg-4 col-md-12" v-click-outside="hidePopUps">
...
</>

you can check this on

Comments:
2023-01-19 23:20:11
How does the method 2 works with iframes?

You can also directly use VueUse vOnClickOUtside directive.

<script setup lang="ts">
import { vOnClickOutside } from '@vueuse/components'
const modal = ref(true)
function closeModal() {
  modal.value = false
}
</script>

<template>
  <div v-if="modal" v-on-click-outside="closeModal">
    Hello World
  </div>
</template>

It might be little late but i ve found a clear solution

<button class="m-search-btn" @click="checkSearch" v-bind:class="{'m-nav-active':search === true}">

methods:{
checkSearch(e){
  var clicked = e.target;
  this.search = !this.search;
  var that = this;
  window.addEventListener('click',function check(e){
    if (clicked === e.target || e.target.closest('.search-input')){ //I ve used target closest to protect the input that has search bar in it
      that.search = true;
    }else {
      that.search = false;
      removeEventListener('click',check)
    }
  })
}}