views:

5825

answers:

12

Suppose I attach an onblur 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 onblur 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 onblur event on the input element. So I want to check in the OnBlur function if one specific element has been clicked, and if so, ignore the blur event.

A: 

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'
}" />
muloh
this doesn't answer the question, hopefully I made it clearer with the additional example
Michiel Borkent
A: 

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.

Armin Ronacher
A: 

Don't attach it that way, because the browsers behave differently. Use a library that handles browser differences for you, like YUI's Event.

Hank Gay
A: 
<input id="myinput" onblur="alert(this.id);"></input>
Catalin DICU
+1  A: 

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

stefano m
+9  A: 

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.

Shog9
I have been looking for something like explicitOriginalTarget for a long time. How did you discover it?
Kev
Examined the event object in FireBug. FWIW, the property is Mozilla-specific, and documented on MDC: http://developer.mozilla.org/en/DOM/event.explicitOriginalTarget
Shog9
Good answer. Very handy.
Joel Anair
You saved my life! Today I've been fighting with this for hours until I found this tip :) Thanks, Joshua!
Danita
This doesn't work (or stopped working?) in Firefox 3.6 and Safari 4.0.3 in Windows.
Chetan Sastry
@Chetan Sastry: It still works in FF 3.6, but... Only in limited circumstances. I've updated this answer with more information.
Shog9
A: 

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.

--
bmb

bmb
A: 

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.

stalepretzel
It's almost the solution, but in the onblur event handler I already needed to know what item had been clicked, so a timeout on the onblur did it for me.
Michiel Borkent
+4  A: 

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.

Michiel Borkent
Is this considered bad practice in javascript world btw?
Michiel Borkent
old post but I have the same question. regardless, it's the only thing that seems to get the job done cross-browser.
joshs
+1  A: 

Hi Michiel,

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.

matte
A: 

keep in mind, that the solution with explicitOriginalTarget does not work for text-input-to-text-input jumps.

try to replace buttons with the following text-inputs and you will see the difference:

<input id="btn1" onblur="showBlur(event)" value="text1">
<input id="btn2" onblur="showBlur(event)" value="text2">
<input id="btn3" onblur="showBlur(event)" value="text3">
A: 

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

$(document).mousedown(function(){
  if ($(event.target).attr("id") == "mySpan") {
    // some process
  }
});