When a 'blur' event occurs, how can I find out which element focus went *to*?

0 votes
asked Sep 23, 2008 by michiel-borkent

Suppose I attach an blur function to an HTML input box like this:

<input id="myInput" onblur="function() { ... }"></input>

Is there a way to get the ID of the element which caused the blur event to fire (the element which was clicked) inside the function? How?

For example, suppose I have a span like this:

<span id="mySpan">Hello World</span>

If I click the span right after the input element has focus, the input element will lose its focus. How does the function know that it was mySpan that was clicked?

PS: If the onclick event of the span would occur before the onblur event of the input element my problem would be solved, because I could set some status value indicating a specific element had been clicked.

PPS: The background of this problem is that I want to trigger an AJAX autocompleter control externally (from a clickable element) to show its suggestions, without the suggestions disappearing immediately because of the blur event on the input element. So I want to check in the blur function if one specific element has been clicked, and if so, ignore the blur event.

20 Answers

0 votes
answered Jan 7, 2008 by matte

I am also trying to make Autocompleter ignore blurring if a specific element clicked and have a working solution, but for only Firefox due to explicitOriginalTarget

Autocompleter.Base.prototype.onBlur = Autocompleter.Base.prototype.onBlur.wrap( 
        function(origfunc, ev) {
            if ($(this.options.ignoreBlurEventElement)) {
                var newTargetElement = (ev.explicitOriginalTarget.nodeType == 3 ? ev.explicitOriginalTarget.parentNode : ev.explicitOriginalTarget);
                if (!newTargetElement.descendantOf($(this.options.ignoreBlurEventElement))) {
                    return origfunc(ev);
                }
            }
        }
    );

This code wraps default onBlur method of Autocompleter and checks if ignoreBlurEventElement parameters is set. if it is set, it checks everytime to see if clicked element is ignoreBlurEventElement or not. If it is, Autocompleter does not cal onBlur, else it calls onBlur. The only problem with this is that it only works in Firefox because explicitOriginalTarget property is Mozilla specific . Now I am trying to find a different way than using explicitOriginalTarget. The solution you have mentioned requires you to add onclick behaviour manually to the element. If I can't manage to solve explicitOriginalTarget issue, I guess I will follow your solution.

0 votes
answered Jan 23, 2008 by armin-ronacher

This way:

<script type="text/javascript">
    function yourFunction(element) {
        alert(element);
    }
</script>
<input id="myinput" onblur="yourFunction(this)">

Or if you attach the listener via JavaScript (jQuery in this example):

var input = $('#myinput').blur(function() {
    alert(this);
});

Edit: sorry. I misread the question.

0 votes
answered Jan 23, 2008 by brock-holum

Edit: A hacky way to do it would be to create a variable that keeps track of focus for every element you care about. So, if you care that 'myInput' lost focus, set a variable to it on focus.

<script type="text/javascript">
   var lastFocusedElement;
</script>
<input id="myInput" onFocus="lastFocusedElement=this;" />

Original Answer: You can pass 'this' to the function.

<input id="myInput" onblur="function(this){
   var theId = this.id; // will be 'myInput'
}" />
0 votes
answered Jan 23, 2008 by stefano-m

i think it's not possibe, with IE you can try to use window.event.toElement, but it dosn't work with firefox!

0 votes
answered Jan 23, 2008 by bmb

Can you reverse what you're checking and when? That is if you remeber what was blurred last:

<input id="myInput" onblur="lastBlurred=this;"></input>

and then in the onClick for your span, call function() with both objects:

<span id="mySpan" onClick="function(lastBlurred, this);">Hello World</span>

Your function could then decide whether or not to trigger the Ajax.AutoCompleter control. The function has the clicked object and the blurred object. The onBlur has already happened so it won't make the suggestions disappear.

0 votes
answered Jan 23, 2008 by stalepretzel

I suggest using global variables blurfrom and blurto. Then, configure all elements you care about to assign their position in the DOM to the variable blurfrom when they lose focus. Additionally, configure them so that gaining focus sets the variable blurto to their position in the DOM. Then, you could use another function altogether to analyze the blurfrom and blurto data.

0 votes
answered Sep 23, 2008 by shog9

Hmm... In Firefox, you can use explicitOriginalTarget to pull the element that was clicked on. I expected toElement to do the same for IE, but it does not appear to work... However, you can pull the newly-focused element from the document:

function showBlur(ev)
{
   var target = ev.explicitOriginalTarget||document.activeElement;
   document.getElementById("focused").value = 
      target ? target.id||target.tagName||target : '';
}

...

<button id="btn1" onblur="showBlur(event)">Button 1</button>
<button id="btn2" onblur="showBlur(event)">Button 2</button>
<button id="btn3" onblur="showBlur(event)">Button 3</button>
<input id="focused" type="text" disabled="disabled" />

Caveat: This technique does not work for focus changes caused by tabbing through fields with the keyboard, and does not work at all in Chrome or Safari. The big problem with using activeElement (except in IE) is that it is not consistently updated until after the blur event has been processed, and may have no valid value at all during processing! This can be mitigated with a variation on the technique Michiel ended up using:

function showBlur(ev)
{
  // Use timeout to delay examination of activeElement until after blur/focus 
  // events have been processed.
  setTimeout(function()
  {
    var target = document.activeElement;
    document.getElementById("focused").value = 
      target ? target.id||target.tagName||target : '';
  }, 1);
}

This should work in most modern browsers (tested in Chrome, IE, and Firefox), with the caveat that Chrome does not set focus on buttons that are clicked (vs. tabbed to).

0 votes
answered Sep 24, 2008 by michiel-borkent

I solved it eventually with a timeout on the onblur event (thanks to the advice of a friend who is not StackOverflow):

<input id="myInput" onblur="setTimeout(function() {alert(clickSrc);},200);"></input>
<span onclick="clickSrc='mySpan';" id="mySpan">Hello World</span>

Works both in FF and IE.

0 votes
answered Jan 3, 2010 by evgeny-shmanev

It's possible to use mousedown event of document instead of blur:

$(document).mousedown(function(){
  if ($(event.target).attr("id") == "mySpan") {
    // some process
  }
});
0 votes
answered Jan 1, 2011 by ericduweb

I've been playing with this same feature and found out that FF, IE, Chrome and Opera have the ability to provide the source element of an event. I haven't tested Safari but my guess is it might have something similar.

$('#Form').keyup(function (e) {
    var ctrl = null;
    if (e.originalEvent.explicitOriginalTarget) { // FF
        ctrl = e.originalEvent.explicitOriginalTarget;
    }
    else if (e.originalEvent.srcElement) { // IE, Chrome and Opera
        ctrl = e.originalEvent.srcElement;
    }
    //...
});
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...