Adding Support for ‘disabled’ OPTION tags in MSIE

This is a very annoying bug/oversight in MSIE (including the recently released MSIE7!).

For some reason, Microsoft didn’t implement the ‘disabled’ attribute on <option> tags.
All other modern (even the old Netscape 4.x) browsers support this, why would they not do the same.
This is probably for the same reason that all versions of MSIE (prior to MSIE7) left the rendering of the SELECT tag to the operating system itself, above the browser HTML.
Thankfully, you can still access the attribute on the DOM element with javascript!

My solution has evolved over time, here’s the current release code.

To emulate this behavior in MSIE, you’ve got several different challenges to overcome.

  1. You must ‘persist’ the current value of the SELECT so that you can ‘restore’ it when the user chooses a disabled field, I do this during the onload event.
  2. When the ‘onchange’ event for the SELECT tag is invoked, the currently selected OPTION’s attributes must be read and checked.
  3. If the selected OPTION is ‘disabled’, then the previous value must be restored.
  • As this solution only stores one value per SELECT, the ‘multiple’ SELECT is not currently supported.
  • In the future I’ll probably do some ‘event injection’ so that the HTML itself is cleaner. Problem is that in more complex solutions like ‘dependent dropdowns’ this becomes tricky.
  • The [if IE] ‘comment’ is critical as it is conditional logic supported only in MSIE and simplifies what was previously done via various ‘browser-sniffing’ tricks.
  • The example code in this example excludes the CDATA escapes and several tags required for valid XHTML for brevity.
  • FYI, the example also contains the MSIE background-image cache fix discussed in a previous post.

<!DOCTYPE >
<html>
<head>
<script type=”text/javascript”>
var isMSIE=false;
<!–[if IE]>
<script type=”text/javascript”>
isMSIE=true;
</script>
<script src=”/js/grv-msie-hacks.js” type=”text/javascript”></script>
<![endif]–>

<script type=”text/javascript”>
function xload(){
if(isMSIE){
grvMsieInitHacks();
}
}
function xchange(obj){
// note: javascript emulation of <option disabled…> (for MSIE)
if(isMSIE){
grvMsieSelectFix_restore(obj);
}
}
</script>
</head>

<body onload=”xload();”>

<form action=”#” method=”GET”>
<select name=”s” id=”s” size=”1″ onchange=”xchange(this);”>
<option value=”n1″>Normal1</option>
<option value=”di” disabled=”disabled”>Dis</option>
<option value=”n1″>Normal2</option>
</select>
</form>
</body>
</html>

JavaScript file (grv-msie-hacks.js):

/*
* Code library to add several ‘broken’ features in MSIE 6 and 7
* @version $Id: $
*/
function grvMsieInitHacks(){
grvMsieCacheFix();
grvMsieSelectFix_init()
}
function grvMsieCacheFix(){
try{
document.execCommand(“BackgroundImageCache”,false,true);
}catch(e)
{}
}
/* Added new functions to support <option disabled…> emulation
*
* First part, necessary for <body onLoad…>
* builds array of all initial selections for <select>s on page (for LT or EQ MSIE7)
* WAS: disabledOptionEmulation();
*/
function grvMsieSelectFix_init() {
if (document.getElementsByTagName) {
var allSelects = document.getElementsByTagName(“select”); // build array of all <select> tags
if (allSelects.length > 0) { // if array has values…
window.allSelectsCurrentIndex = new Array(); // new array to hold initial selections
for (var i=0, individualSelect; individualSelect = allSelects[i]; i++) { // crawl through all <select> tags
individualSelect.onfocus = function(){ window.allSelectsCurrentIndex[this.id] = this.selectedIndex; } // fill array with selectedIndex values
}
}
}
}

/* companion code for grvMsieSelectFix_init()
* resets <option> selection if disabled to last good selection (for LT or EQ MSIE7)
* WAS: restoreSelection(inOptionChoice)
*/
function grvMsieSelectFix_restore(inOptionChoice) {
if (inOptionChoice.options[inOptionChoice.selectedIndex].disabled){
// if new choice is disabled…
inOptionChoice.selectedIndex = window.allSelectsCurrentIndex[inOptionChoice.id]; // deny selection, revert back to last ‘known good’ choice (typically, the initial selection at page load)
} else { // if new choice isn’t disabled…
window.allSelectsCurrentIndex[inOptionChoice.id] = inOptionChoice.selectedIndex; // update array so last ‘known good’ choice is now the latest user selection
}
}

Hopefully, Microsoft will get around to fixing this correctly some day… maybe for MSIE8!

Leave a Reply