2005/10/23

Another stupid IE bug: selectedIndex on IE6

Presupposing these functions:

function addNewOption(select, value, label) {
var option = document.createElement("option");
option.setAttribute("value", value);
option.appendChild(document.createTextNode(label));
select.appendChild(option);
}

function getOptionIdx(select, value) {
if(!select.options) return -1;
for(var oNum = 0; oNum != select.options.length; oNum++) {
if(select.options[oNum].value == value) return oNum;
}
return -1;
}
Now watch carefully:
var optVal = "1";
var select = $("exampleSelect"); //prototype shortcut

addNewOption(select, optVal, "one");

This code retrieves a select by ID and adds an option to it. (The select is a single-value select.) The following code selects that option:

select.selectedIndex = getOptionIdx(select, optVal);


Or it would do, if it worked in IE. Apparently selectedIndex is readonly in IE4, which I don't care about. However, selectedIndex is also readonly in IE6, under certain circumstances, but it just fails silently. The workaround for the IE4 bug was as follows:

select.options[getOptionIdx(select, optVal)].selected = true;

This fails in IE6 with the stunningly unhelpful message "Could not set the selected property. Unspecified error."

HOWEVER, this code does work:

var optIdx = getOptionIdx(select, optVal);

alert("optIdx="+optIdx);

select.options[optIdx].selected = true; // [1]


Removing the alert (or logging statement or whatever) gets you straight back to square one. Wierder still, surrounding [1] with a try-catch block will throw an "undefined" error, and set the select to the value, which I guess is the workaround I need.

Needless to say, I don't have this problem on FireFox. My completely uneducated guess is that DOM tree operations are slightly asynchronous, and that the time it took for the JS interpreter to move onto the next instruction was longer than the time it took for the DOM update thread to finish making changes, when computers were slower than they are now. I have no idea.

17 comments:

Anonymous said...

This workaround may be for some who found this post by searching for a solution to this problem (I didn't find one so I had to come up with this myself).

The problem was appearing for me in an onLoad call, might be the same with a call from embedded script I suspect. I noted also that an alert() with the code would make it work so I figured that maybe it's a problem with the page loading procedure and interrputing that helps.. So why not break out of the onLoad?

My solution is to put a setTimeout() call to my option setting function in the function called by onLoad. So it now looks like: setTimeout("initSelections()", 100); with function initSelections() {} doing the select.selectedIndex = X; and working properly.

100ms is fine for me, I suspect it could go lower and still be fine.

Anonymous said...

IE is awful.
I encountered this problem during work, and since I had to fix multiple select boxes the setTimeout solution wasn't working for me, as the pointer for the option already changed by the time it executed the script.

Anyways, here is a fix that actually worked for IE. instead of using
ele.selected = true;
I used
ele.setAttribute('selected',true);

And it actually worked.

Conclusion: If I spent as much time writing real code at work instead of fixing IE-specific bugs, you would have all known me by now.

Anonymous said...

I'm struggling with this bug right now (I'm trying to set a [select] to a default value on [body onload]). I've tried all of the suggested solutions, but none of them work.

Annoyingly, IE refuses to recognize the options property of my select element - it keeps saying that it's null or not an object. This remains true even if I use the window.setTimeout() method to delay execution by 500ms.

I really, really hate IE6. Thanks for the post, though - it's at least given me somewhere to start.

Anonymous said...

Do the following:

while(true) try { option.selected = true; break; } catch(e) {}

It solves this stupid MSIE bug (a kind of synchronization/locked variable error)

Thanks for your insights

Jose M. Arranz

Anonymous said...

A finer solution:

if (option.selected != myValue)
while(true) try { option.selected = myValue; break; } catch(e) {}

Otherwise could enter in an infinite loop.

Jose M. Arranz
JNIEasy: C/C++ meets Java

Anonymous said...

This is really a GREAT help, thanks a lot .!

Anonymous said...

This was of great help. Using setAttribute works like a charm! Thanks a lot

Anonymous said...

Thanks a lot, a whole wasted afternoon was ended by this article

Anonymous said...

Thanks a lot, it solved my problem.

Unknown said...

Great bit of info for selecting multiple options in internet explorer

Jayasri said...

great help... I found this useful
thanks

Anonymous said...

Great help.. Thanks

ZAYAR said...

Thanks. This save my life.

Anonymous said...

the option tag requires a value attribute in IE. Simply set the value to the same value that is between the option tags and you're set.

ie (no pun intended)
select
option value="Blue">Blue option
option value="Red">Red option
select

(Sorry, blogger doesn't allow full tags)

Then IE can access it with JavaScript by element.value.

Anonymous said...

Thanks for posting this. Keep up the good work!

RollerCoaster said...

thanks this worked for me-
try { dropdown.selectedIndex = i; } catch (e) { };

My select code was in one of the functions called onLoad as well but I didnt need to try the setTimeOut option though that has worked for me before when I am manipulating the DOM from a function within onLoad on IE

RollerCoaster said...

ok it didnt work as i specified above. that only works when i do Ctrl+F5

had to use the recursive stuff-

if (dropdown.options[i].selected != true) while (true) try { dropdown.options[i].selected = true; break; } catch (e) { }

I feel sad :(