2

Quite simple. I have a blur() event handler that fires a function, I want the function not to fire when the blur is triggered by the click on a certain element.

I tried document.activeElement but i get a HTMLBodyElement instead of the element I click on.

code:

$j(".input_filtrare_camp").blur(
    function(event) {
    nr_img = this.parentNode.id.split("_")[1];
    //alert(document.activeElement);
    if(document.activeElement.id.indexOf("img_exact") < 0) //run only if the id of the element I clicked on doesn't contain "img_exact"
        enter_input_filtrare(event.target);                                                                         
});

the alert is for troubleshooting, of course.

I used techfoobar's solution as follows:

var currElem = null;

$(document).mousedown(function(e) {
    currElem = e.target;
});

$j(".input_filtrare_camp").blur(
    function(event) {
    nr_img = this.parentNode.id.split("_")[1];
    if(currElem.id.indexOf("img_exact") < 0) //run only if the id of the element I clicked on doesn't contain "img_exact"
        enter_input_filtrare(event.target);                                                                         
});

Check out PointedEars' answer for some important information regarding this issue.

Bogdan
  • 1,869
  • 6
  • 24
  • 53

4 Answers4

7

The following code will tell you where focus went to, it requires a setTimeout, because like others have said, when the blur fires, the new element may not have received focus. The real trick though, is to know that document.activeElement holds the element that has focus. This answer will work even when focus changes for other reasons besides clicking

http://jsfiddle.net/mendesjuan/crenZ/

HTML

<input id="inp1" />
<input id="inp2" />

JS See Detect which form input has focus using JavaScript or jQuery

$('input').blur(function(){
    // Need a setTimeout
    // There is no guarantee of where the focus went, but after the 
    // current event is processed, it will be available
    setTimeout(function(){
        // The currently focused element 
        console.log(document.activeElement);
    }, 0);
})​
Community
  • 1
  • 1
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • Seems like the only answer on this page which actually works! A pity I can only +1; it certainly deserves +many and the green tick! – Tom Jul 22 '12 at 21:03
2

Check this fiddle:

http://jsfiddle.net/pHQwH/

The solution sets the active element on document's mousedown which is triggered for all elements in the document and uses that to determine whether or not to executed the code in blur event.

CODE


var currElem = null;

$(document).mousedown(function(e) {
    currElem = e.target;
});

$('#f1').blur(function() {
    if(currElem != null && currElem.id != "f3") {
        $(this).val('F1: clicked elem is not f3, blur event worked');
        // do your blur stuff here
    }
    else {
        // for demo only, comment this part out
        $(this).val('F1: clicked elem is f3, no blur event');
    }
});
techfoobar
  • 65,616
  • 14
  • 114
  • 135
  • 2
    Put the code there. What is jsfiddle is down tomorrow? Your answer won't mean anything. – Florian Margaine May 29 '12 at 07:40
  • Interesting idea, but event order is not guaranteed there, and elements can receive the focus without using a pointing device. See my answer. – PointedEars May 29 '12 at 08:32
  • Actually, I'm pretty sure that mousedown happens before blur, click and focus. But this still won't work if focus is lost with the keyboard. My answer does address that. – Ruan Mendes Jun 15 '12 at 18:02
1

Use event.target - The target event property yields the element that triggered the event.

<html>
<head>

<script type="text/javascript">
  function getEventTrigger(event)
  {
    var x=event.target;
    window.alert("The id of the triggered element: " + x.id);
  }
</script>

</head>
<body >

<p id="p1" onmousedown="getEventTrigger(event)">
Click on this paragraph. An alert box will
show which element triggered the event.</p>

</body>
</html>
PointedEars
  • 14,752
  • 4
  • 34
  • 33
Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
  • but I need the element that was clicked on in the context of the blur event bound to another element. – Bogdan May 29 '12 at 07:29
  • The answer does not address the question. Also, it's _property_, not attribute (we are not talking interfaces here), and it should be `window.alert`. – PointedEars May 29 '12 at 07:31
  • @Bogdan - that what i said in my answer use : var x=event.target; x.id is give you the element id... – Pranay Rana May 29 '12 at 07:34
  • @Bogdan - just replace this document.activeElement.id with this var x=event.target; x.id line of code... – Pranay Rana May 29 '12 at 07:35
  • @PranayRana but in this case the event.target is the input that has the blur handler attached to it. As you can see I use it as a parameter for my function. What I need is the element I clicked on to trigger this blur event. For example: I have the input focused, when I click somewhere else, the blur handler on the input fires. I want to know which element I clicked on to trigger the blur event. – Bogdan May 29 '12 at 07:39
0

This is not possible with a blur event listener alone. The blur event – which it is triggered by – occurs when an element loses focus. The click event occurs after an element receives focus, after the focus event for the same element. As a result, there is a state in-between in which neither element has the focus:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>DOM Test Case: Event Order</title>
    <script type="text/javascript">
      function debugEvent (event)
      {
        /* or window.alert(…); */
        console.log(event, "on", event.target || window.event.srcElement);
      }

      function body_load ()
      {
        var elements = document.forms[0].elements;
        var foo = elements["foo"];
        var bar = elements["bar"];
        foo.onblur = bar.onfocus = bar.onclick = debugEvent;
      }
    </script>
  </head>
  <body onload="body_load()">
    <h1>DOM Test Case: Event Order</h1>
    <form action="">
      <div>
        <input name="foo">
        <input name="bar">
      </div>
    </form>
  </body>
</html>

See also: DOM Level 2 Events Specification: HTML Events

What you could do is to use a listener for an event that occurs before the blur event. The mousedown event suggested by @techfoobar appears to be such an event (in Chromium 18.0.1025.168 (Developer Build 134367 Linux)), but there is no standard, no draft specification even, to back that up¹. See also: What is the event precedence in JavaScript?

Anyhow, that solution is incomplete as both a blur event and a click event may be triggered also by pressing a key (combination), for example. Handling the keydown event should help then, but the solution would still be incomplete.

Therefore, it is likely that your approach is wrong.


¹ Of course, if you are limiting yourself to jQuery and similar libraries (which the $j() calls indicate), you could also satistfy yourself to testing in the subset of browsers that they claim to support. But you will have to re-test that with every new browser, and every new version of browser and library.

Community
  • 1
  • 1
PointedEars
  • 14,752
  • 4
  • 34
  • 33
  • I understand, but it's not important to me how it loses focus in any way other than clicking on a certain type of element. It's basically like this: If you write some stuff in the input and then change focus from it, do_this(); but if the focus is lost by clicking this element here don't do_this() because the onclick of said element already does the do_this() thing after making some specific changes to the input value. That said, I have noticed some hiccups on slower connections/slower devices but nothing important and the project manager gave it the go-ahead for live. – Bogdan May 30 '12 at 11:08
  • From the blur handler, the `document.activeElement` returns `document.body`, so yeah, you can't know from the blur handler itself, . http://jsfiddle.net/mendesjuan/crenZ/1/ Unless you use a `setTimeout` which I suggested in my answer – Ruan Mendes Jun 15 '12 at 17:43
  • @JulianMendes No, that is the race condition I mentioned. And `setTimeout()` without timeout value is a liability because behavior is implementation-dependent. – PointedEars Jun 17 '12 at 06:35
  • @PointerEars, If the problem with my approach is that I'm not passing a delay, then juss pass 0. All I'm trying to do is let the event handling thread finish and let the focus move to where it may, then use `document.activeElement`. Sorry this is late, but your @ tag had my name mispelled – Ruan Mendes Dec 05 '13 at 19:17
  • @JuanMendes `0` is not reliable either. BTW: I saw your reply despite the misspelling. – PointedEars Dec 08 '13 at 09:42