Reputation: 15372
I have a text input that I would like to, when it has focus, register a click event anywhere on the body
. But when focus is removed from it, that click event is removed from the body
. Sadly, I seem not to be able to suss it.
$(document).ready(function () {
$("html").on("focus", "#asdf", function () {
$("body").on("click", "*:not(#asdf)", wasItClicked);
});
$("html").on("blur", "#asdf", function () {
$("body").off("click", "*", wasItClicked);
});
});
function wasItClicked() {
alert("yeah");
}
Thanks for any help.
Upvotes: 0
Views: 364
Reputation: 4294
Ok, I see a couple of issues...
focus
and blur
events directly on the input
off
, you need to pass it the exact same selector in the second parameterbody
itself... not sure if you wanted it that way, but I moved it up to the html
element, to include the body
input
loses focus, the event will be removed, so the clicks won't register (You can use a timeout as @HMR suggested in their answer)I had some problems with the delegation on the html
element that was still returning the input (despite the :not(#asdf)
selector) so I just put the filter into the function.
Here is the revised code (testing version):
var click_selector = ":not(#asdf)";
var click_target = 'html';
$(document).ready(function () {
$("#asdf").on("focus", function () {
$(click_target).on("click", click_selector, wasItClicked);
});
$("#asdf").on("blur", function () {
// Use timeout to be able to register the click before function is removed
// NOTE that since 'click' fires when the mouse is released, if they
// hold the mouse down for a while, the event will be gone and won't
// register. Maybe better to use 'mousedown' instead of 'click'
// in which case the timeout could probably be reduced to 10ms or something
// Also, using timeouts creates the possibility of multiple click handlers
// present at the same time (new one added before the previous is removed)
setTimeout( function(){
$(click_target).off("click", click_selector, wasItClicked);
}, 100);
});
});
function wasItClicked(e) {
e.stopPropagation();
e.preventDefault();
if( e.target.id !== 'asdf' ){
console.log('yeah', click_target, click_selector);
}
}
Upvotes: 0
Reputation: 28336
When #asdf is focused, and some other element is clicked, The events fire in order mousedown, blur, mouseup, click. So the handler has been removed before click fires.
The mousedown event fires before blur. If you are OK with mousedown instead of click, you could use this:
$(document).ready(function () {
$("#asdf").on("focus", function () {
$("body").on("mousedown", wasItClicked);
});
$("#asdf").on("blur", function () {
$("body").off("mousedown", wasItClicked);
});
});
Edit:
You could use the mousedown event to help determine if you are losing focus because of a click, and remove the handler in the click handler if have lost focus.
$(document).ready(function () {
$("#asdf").on("focus",function() {
$("body").on("mousedown", setDown);
$("body").on("click", wasItClicked);
});
$("#asdf").on("blur", function() {
if ($(this).attr("mouse") != "down") {
$("body").off("mousedown", setDown);
$("body").off("click", wasItClicked);
}
});
});
function setDown() {
$("#asdf").attr("mouse","down");
}
function wasItClicked() {
if ($("#asdf") != $(document.activeElement)) {
$("body").off("mousedown", setDown);
$("body").off("click", wasItClicked);
}
$("#asdf").attr("mouse","up");
alert("yeah");
}
Upvotes: 1
Reputation: 39270
You could use setTimeout to remove the click and use namespaces when adding and removing events because you may accidentally remove another click handler but the simplest way would be to remove the click event in the handler:
...
$("body").on("click.fromasf", "*:not(#asdf)", wasItClicked);
...
function wasItClicked() {
$("body").off("click.fromasf");
console.log("yeah");
}
Here is an example using timeout:
<!DOCTYPE html>
<html>
<head>
<script src="jquery-1.9.0.js"></script>
<style>
</style>
<meta content="text/html; charset=UTF-8" http-equiv="content-type">
<title>Example</title>
</head>
<body>
<input type="text" id="asdf" />
<input type="text" id="Text1" />
<script>
$(document).ready(function () {
$("html").on("focus", "#asdf", function () {
console.log("adding click handler");
$("body").on("click.fromasf", "*:not(#asdf)", wasItClicked);
});
$("html").on("blur", "#asdf", function () {
setTimeout(function () {
console.log("remove click");
$("body").off("click.fromasf");
}, 500);
});
});
function wasItClicked() {
console.log("yeah");
}
</script>
</body>
</html>
Upvotes: 0