Click Everywhere But Here Event

Click everywhere but here event

EDIT: There were a couple of problems in this old, old answer.

*Also: Marking Community Wiki (no points for me) because errors

  1. N calls for N uses of the directive. This probably isn't desirable for uses within the same scope with matching expressions.

  2. NOTHING WAS TEARING DOWN THE EVENT HANDLERS!!!! BAD! BAD! BAD!

So, I'm updating this answer. Hopefully it didn't cause anyone too much trouble.

Updated answer

Here's a new plunker with those issues fixed ... there are likely other things that individual application developers will run into. This is just an example of how to handle this problem.

app.factory('clickAnywhereButHereService', function($document){
var tracker = [];

return function($scope, expr) {
var i, t, len;
for(i = 0, len = tracker.length; i < len; i++) {
t = tracker[i];
if(t.expr === expr && t.scope === $scope) {
return t;
}
}
var handler = function() {
$scope.$apply(expr);
};

$document.on('click', handler);

// IMPORTANT! Tear down this event handler when the scope is destroyed.
$scope.$on('$destroy', function(){
$document.off('click', handler);
});

t = { scope: $scope, expr: expr };
tracker.push(t);
return t;
};
});

app.directive('clickAnywhereButHere', function($document, clickAnywhereButHereService){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
var handler = function(e) {
e.stopPropagation();
};
elem.on('click', handler);

scope.$on('$destroy', function(){
elem.off('click', handler);
});

clickAnywhereButHereService(scope, attr.clickAnywhereButHere);
}
};
});

Original answer (with fixes for teardown of event handlers)

You were close with the one answer you've found, but I've put together a plunk for you to show you what it was missing.

app.directive('clickAnywhereButHere', function($document){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
var elemClickHandler = function(e) {
e.stopPropagation();
};

var docClickHandler = function() {
scope.$apply(attr.clickAnywhereButHere);
};

elem.on('click', elemClickHandler);
$document.on('click', docClickHandler);

// teardown the event handlers when the scope is destroyed.
scope.$on('$destroy', function() {
elem.off('click', elemClickHandler);
$document.off('click', docClickHandler);
});
}
}
})

HTML

<a click-anywhere-but-here="clickedSomewhereElse()" 
ng-click="clickedHere()">Don't Click Me!</a>

JQuery: click everywhere but some element

$(document).click(function(e) {
if ( $(e.target).closest('#menu').length === 0 ) {
// cancel highlighting
}
});

An alternative solution would be to call stopPropagation() at the end of the #menu click handler and element click handlers. That way, if a click event bubbles to the document object, you know that neither the menu nor the elements were clicked and you can safely cancel the highlighting:

$('#menu').click(function(e) {
// do stuff
e.stopPropagation();
});

$('.element').click(function(e) {
//do stuff
e.stopPropagation();
});

$(document).click(function() {
// cancel highlighting
});

Event on a click everywhere on the page outside of the specific div

Attach a click event to the document to hide the div:

$(document).click(function(e) {
$('#somediv').hide();
});

Attach a click event to the div to stop clicks on it from propagating to the document:

$('#somediv').click(function(e) {
e.stopPropagation();
});

How do I handle a click anywhere in the page, even when a certain element stops the propagation?

Events in modern DOM implementations have two phases, capturing and bubbling. The capturing phase is the first phase, flowing from the defaultView of the document to the event target, followed by the bubbling phase, flowing from the event target back to the defaultView. For more information, see http://www.w3.org/TR/DOM-Level-3-Events/#event-flow.

To handle the capturing phase of an event, you need to set the third argument for addEventListener to true:

document.body.addEventListener('click', fn, true); 

Sadly, as Wesley mentioned, the capturing phase of an event cannot be handled reliably, or at all, in older browsers.

One possible solution is to handle the mouseup event instead, since event order for clicks is:

  1. mousedown
  2. mouseup
  3. click

If you can be sure you have no handlers cancelling the mouseup event, then this is one way (and, arguably, a better way) to go. Another thing to note is that many, if not most (if not all), UI menus disappear on mouse down.

JQuery : Click Everywhere But Some Element?

Since you mentioned you have event.stopPropagation() at different sections of the page on click event so document.click will not work to hide the textbox.

Why don't you use document.mousedown? It will work fine.

$(document).mousedown(function(){
$('textboxSelector').hide();
});

Make sure you stop the mousedown event propagation from textbox and its containing div.

jQuery click anywhere in the page except on 1 div

You can apply click on body of document and cancel click processing if the click event is generated by div with id menu_content, This will bind event to single element and saving binding of click with every element except menu_content

$('body').click(function(evt){    
if(evt.target.id == "menu_content")
return;
//For descendants of menu_content being clicked, remove this check if you do not want to put constraint on descendants.
if($(evt.target).closest('#menu_content').length)
return;

//Do processing of click event here for every element except with id menu_content

});

Angular.js closing with click anywhere but on the element

The way I've tackled things like this before is using inheritedData to communicate to the click handler whether it's in or out of the thing:

  • In the custom directive for the thing, add a data variable to the element, using jqLite data, say element.data('myThing',true) . If you want to distinguish between multiple instances of the the thing, you might need to use some uniquely generated key.

  • In the same custom directive, in a click event handler on document.body, you can check angular.element(event.target).inheritedData('myThing')

An example directive that uses this technique is below

app.directive('thing', function($document,$window) {
return {
restrict: 'E',
template: '<div><span>Inner thing</span></div>',
replace: true,
link: function(scope,element) {
element.data('thing',true);

angular.element($document[0].body).on('click',function(e) {
var inThing = angular.element(e.target).inheritedData('thing');
if (inThing) {
$window.alert('in');
} else {
$window.alert('out');
}
})
}
}
});

and can be seen in this Plunker http://plnkr.co/edit/bRDLcLoesM7Z0BIxKxYu?p=preview

How do I hide an element on a click event anywhere outside of the element?

If I understand, you want to hide a div when you click anywhere but the div, and if you do click while over the div, then it should NOT close. You can do that with this code:

$(document).click(function() {
alert("me");
});
$(".myDiv").click(function(e) {
e.stopPropagation(); // This is the preferred method.
return false; // This should not be used unless you do not want
// any click events registering inside the div
});

This binds the click to the entire page, but if you click on the div in question, it will cancel the click event.

Javascript: Click anywhere in body except the one element inside it

You need to stopPropagation to the outer element.

Here's a simple illustration: http://jsfiddle.net/5mhqrhwk/3/

var body = document.getElementById('wrapper');
var except = document.getElementById('except');

body.addEventListener("click", function () {
alert("wrapper");
}, false);
except.addEventListener("click", function (ev) {
alert("except");
ev.stopPropagation(); //this is important! If removed, you'll get both alerts
}, false);

HTML:

<div id="wrapper">
<center>
<div id="except"></div>
</center>
</div>


Related Topics



Leave a reply



Submit