Detect External Element (Vanilla JavaScript)

I have been looking for a good solution all over the world, but I cannot find one that does not use jQuery .

Is there a cross browser, the usual way (without weird hacks or easy to break code) to detect a click outside the element (which may or may not have children)?

+42
javascript
Jan 07 '13 at 1:21
source share
4 answers

Add an event listener to the document and use Node.contains() to find out if the purpose of the event (which is the topmost element clicked) is inside the specified element. It works even in IE5

 var specifiedElement = document.getElementById('a'); //I'm using "click" but it works with any event document.addEventListener('click', function(event) { var isClickInside = specifiedElement.contains(event.target); if (!isClickInside) { //the click was outside the specifiedElement, do something } }); 

 var specifiedElement = document.getElementById('a'); //I'm using "click" but it works with any event document.addEventListener('click', function(event) { var isClickInside = specifiedElement.contains(event.target); if (isClickInside) { alert('You clicked inside A') } else { alert('You clicked outside A') } }); 
 div { margin: auto; padding: 1em; max-width: 6em; background: rgba(0, 0, 0, .2); text-align: center; } 
 Is the click inside A or outside? <div id="a">A <div id="b">B <div id="c">C</div> </div> </div> 
+63
Feb 10 '15 at 12:50
source share

You need to handle the click event at the document level. In the event object, you have the target property, the innermost DOM element that was clicked. With this, you test yourself and approach the parents to the document element if one of them is your observed element.

See an example in jsFiddle

 document.addEventListener("click", function (e) { var level = 0; for (var element = e.target; element; element = element.parentNode) { if (element.id === 'x') { document.getElementById("out").innerHTML = (level ? "inner " : "") + "x clicked"; return; } level++; } document.getElementById("out").innerHTML = "not x clicked"; }); 

As always, this is not cross browser compatible due to addEventListener / attachEvent, but it works as follows.

A child is pushed, if not event.target, but one of its parents is an observable (I just count the level for this). You may also have boolean var if the element is found or not, so as not to return a handler from the for clause. My example limits the fact that the handler ends only when nothing matches.

When adding cross-browser compatibility, I usually do it like this:

 var addEvent = function (element, eventName, fn, useCapture) { if (element.addEventListener) { element.addEventListener(eventName, fn, useCapture); } else if (element.attachEvent) { element.attachEvent(eventName, function (e) { fn.apply(element, arguments); }, useCapture); } }; 

This is cross-browser compatible code for attaching a listener / event handler, including rewriting this in IE as an element, like jQuery for event handlers. There are many arguments to keep in mind a few jQuery bits;)

+25
Jan 07 '13 at 1:28
source share

How about this:

JSBBIN-Demo

 document.onclick = function(event){ var hasParent = false; for(var node = event.target; node != document.body; node = node.parentNode) { if(node.id == 'div1'){ hasParent = true; break; } } if(hasParent) alert('inside'); else alert('outside'); } 
+6
Jan 07 '13 at 1:37
source share

To hide an element behind a click outside it, I usually use this simple code:

 var bodyTag = document.getElementsByTagName('body'); var element = document.getElementById('element'); function clickedOrNot(e) { if (e.target !== element) { // action in the case of click outside bodyTag[0].removeEventListener('click', clickedOrNot, true); } } bodyTag[0].addEventListener('click', clickedOrNot, true); 
0
Oct 31 '16 at 13:33
source share



All Articles