admin管理员组

文章数量:1312991

I have an HTML along the following lines:

<div class="hiddenClass"> // this implies display:none
 <span>
    <input type="text" id="hiddenInput"/>
 </span>
</div>

and a Javascript event (triggered in a "succes" method of an jQuery $.ajax() call ), that needs to make this div visible and then set the focus to the control. Something like:

 this.DOMElements.divElement.className="showClass"; //a CSS class with display:block;
 this.DOMElements.hiddenInputElement.focus();
 this.DOMElements.hiddenInputElement.select();

strange enough, this code only works part of the time. In some cases (only sometimes!!) the focus/select mands generate warnings about focusing/selecting an invisible control. The control will be made visible, but the focus is not moved, nor is the text selected.

I found (somewhat) of a solution by moving the focus/select code in a separate function and delay-call it by means of a

this.DOMElements.divElement.className="showClass"; //a CSS class with display:block;
setTimeout("focusinput('hidddenInput')",1);

Ok, finally my question: since javascript is single-threaded.. how e there is a delay between the time I made the parent div visible, and the time I can set the focus/select on the child input element ? How could this be a race condition?

Edit: Happens in IE8

I have an HTML along the following lines:

<div class="hiddenClass"> // this implies display:none
 <span>
    <input type="text" id="hiddenInput"/>
 </span>
</div>

and a Javascript event (triggered in a "succes" method of an jQuery $.ajax() call ), that needs to make this div visible and then set the focus to the control. Something like:

 this.DOMElements.divElement.className="showClass"; //a CSS class with display:block;
 this.DOMElements.hiddenInputElement.focus();
 this.DOMElements.hiddenInputElement.select();

strange enough, this code only works part of the time. In some cases (only sometimes!!) the focus/select mands generate warnings about focusing/selecting an invisible control. The control will be made visible, but the focus is not moved, nor is the text selected.

I found (somewhat) of a solution by moving the focus/select code in a separate function and delay-call it by means of a

this.DOMElements.divElement.className="showClass"; //a CSS class with display:block;
setTimeout("focusinput('hidddenInput')",1);

Ok, finally my question: since javascript is single-threaded.. how e there is a delay between the time I made the parent div visible, and the time I can set the focus/select on the child input element ? How could this be a race condition?

Edit: Happens in IE8

Share Improve this question edited Sep 9, 2009 at 18:40 Radu094 asked Sep 9, 2009 at 18:21 Radu094Radu094 28.4k16 gold badges65 silver badges80 bronze badges 1
  • Happens only in IE I presume? – Crescent Fresh Commented Sep 9, 2009 at 18:24
Add a ment  | 

4 Answers 4

Reset to default 2

If you're using jQuery, use this to display and set focus:

$(".hiddenClass").fadeIn("fast", 
    function() {
        $("#hiddenInput").focus();
    }
);

or

$(".hiddenClass").show(0, 
    function() {
        $("#hiddenInput").focus();
    }
);

If you want to show it without any fade in.

Basically it's fading the hidden div in (you can replace .hiddenClass with an id if you one want a particular div to be shown and not all elements with .hiddenClass), and once it's done that it executes the callback function to give focus to the input.

That way you it will not try to give the input focus until after the div has been fully shown.

Ok, finally my question: since javascript is single-threaded.. how e there is a delay between the time I made the parent div visible, and the time I can set the focus/select on the child input element ?

You just answered your own question: this happens because JS is single-threaded; that is, it blocks the browser from updating its rendering until the script has finished executing.

So when you execute the code:

divElement.className="showClass";

the className property of the element has been updated, but as your script is still executing, the element is not immediately redrawn as visible. Therefore, when you execute

hiddenInputElement.focus();

the element is still hidden and you get the error.

So, in your first version, the sequence of execution in the single thread is:

  1. Script sets className;
  2. Script sets focus;
  3. Browser throws exception because focused element is hidden;
  4. Script ends because of error;
  5. Browser updates things based on the change(s) made by the script up to the point of failure.

When you use the setTimeout approach, the sequence is:

  1. Script sets className;
  2. Script ends;
  3. Browser updates things based on the change(s) made by the script;
  4. Timeout fires;
  5. Timeout script sets focus, which now succeeds.

I'm not sure what's going on here, but it might not be a bad idea to grab a reference to the div your using, store it in a variable, and then operate on that, instead of grabbing it with getElementByID() each time.

So you're above code would be:

 var myDiv = document.getElementById("hiddenInput");
 if(myDiv)
 {
    myDiv.className="showClass"; //a CSS class with display:block;
    myDiv.focus();
    myDiv.select();
 }

Also: There are certain javascript functions where the browser is allowed to spin up another thead (for instance, the load() function); just something to keep in mind :)

I've had this happen to me before. In most cases, I found that by setting a timeout after the setting the display fixes the issue in IE. Unfortunately, it isn't the cleanest fix.

本文标签: javascriptSetting focus on an input element after setting displayblockStack Overflow