1

I want to detect clicking outside an element using class name as selector

<div id="popOne" class="pop">...</div>
<div id="popTwo" class="pop">...</div>
...
<div id="popLast" class="pop">...</div>


<script>
    var popElement = document.getElementById("pop");
    document.addEventListener('click', function(event) {
        var isClickInside = popElement.contains(event.target);
        if (!isClickInside) {
            alert("Outside");
            //the click was outside the popElement, do something
        }
    });
</script>
ARUN KUMAR
  • 428
  • 1
  • 8
  • 19
  • try this http://stackoverflow.com/questions/18893144/javascript-detect-click-event-outside-of-div – M14 Jan 17 '17 at 11:33
  • 1
    @M14 But I want to do it with a class selector – ARUN KUMAR Jan 17 '17 at 11:37
  • I actually had a different way of going about this that I used when developing a game a few years ago. If nothing here really fits the bill let me know and I'll resurrect the code. Something that would be helpful, post a use-case so we have some context (there are at least a dozen ways to do what you're asking but I remember for me none of them were ideal). – Tim Consolazio Jan 17 '17 at 11:37
  • What do you mean "click outside an element?" – Dellirium Jan 17 '17 at 11:43
  • your code is working fine if you are writing script in html then write that above your html element – Akshay Jan 17 '17 at 11:43

3 Answers3

3

As an alternative to iterating over all possible .pop elements for every click event, just traverse the DOM looking to see if the node or any ancestor thereof has the desired class:

document.addEventListener('click', function(e) {
    var node = e.target;
    var inside = false;
    while (node) {
        if (node.classList.contains('pop')) {
            inside = true;
            break;
        }
        node = node.parentElement;
    }

   if (!inside) {
       alert('outside');
       // click was outside
   } else {
       alert('inside');
    }
});

This would make the performance scale relative to the depth of the DOM tree, rather than by the number of .pop elements.

asp
  • 743
  • 2
  • 9
  • 29
Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Found a typing mistake within this code snippet `var node = event.target` needs to change as `event` to `e` or viseversa – asp Jan 19 '17 at 03:49
2

Made the following changes to the script

var popElement = document.getElementsByClassName("pop");
document.addEventListener('click', function(event) {
    for(i=0; i < popElement.length; i++){
        popEl = popElement[i];
        var isClickInside = popEl.contains(event.target);
        if (!isClickInside) {
            alert("Outside");
        } else {
            alert("Inside");
            break;
        }
    }
});
asp
  • 743
  • 2
  • 9
  • 29
  • 1
    NB: this code as written will produce an alert for _every_ element of that class. It would be better written to 'break' the loop as soon as a match is found (or perhaps use the ES6 function `Array.prototype.some`) – Alnitak Jan 17 '17 at 11:51
  • no, this now only tests the first element in the list. The `break` should only happen on the `isClickInside` case, and the `alert()` when that's not true should be omitted. – Alnitak Jan 17 '17 at 11:55
  • Looking further, this code actually can't work (and never did). It tells you whether the click was inside or outside any specific `.pop` element, but not whether it was outside _all_ such elements. – Alnitak Jan 17 '17 at 12:06
1

First of all you are using the incorrect function to get Element. It should be getElementsByClassName("pop") and not getElementsById("pop") and also getElementsByClassName returns a HTMLCollection of elements having that class. So you need to loop over them and check whether clicked inside any of them or not. Here is the demo. Have added some style to divs so that it easy to differentiate between them. And also if need to check whether the click was on any of the divs then you need to check for that and as soon as you find that it was clicked inside a div having class pop. Break from the loop and continue with you conditions. But if for all the elements the IsClickedInside comes out to be false then you can handle it accordingly

 document.addEventListener('click', function(event) {
   var popElement = document.getElementsByClassName("pop");
   var isClickInside;
   for (var i = 0; i < popElement.length; i++) {
     isClickInside = popElement[i].contains(event.target);
     if (isClickInside) {
         break;
        //alert("Outside of" + popElement[i].id);
       //the click was outside the popElement, do something
     }
   }
  if(isClickInside){
     alert("Clicked inside one of the divs.");
   }else{
     alert("Clicked outside of the divs."); 
   }
 });
div {
  height: 100px;
  border:2px solid black;
}
<div id="popOne" class="pop">...</div>
<div id="popTwo" class="pop">...</div>
...
<div id="popLast" class="pop">...</div>

Hope it helps :)

Manish
  • 4,692
  • 3
  • 29
  • 41