Activating option disabled in IE

In Internet Explorer, the attribute "disabled" fails if used in tag option. See here a javascript to simulate the "disabled" attribute in Internet Explorer.

This code will execute and disable option in Standard browsers (FF, Op, etc):

<select>
   <option>opt 1</option>
   <option disabled="'disabled'">opt 2</option>
   <option>opt 3</option>
</select>

In IE, it will fail.

The above code, simulates the attribute "disabled" to IE, using JavaScript. Try-it:

<!--[if lte IE 7]>
<script>
function ativaOptionsDisabled(){
    var sels = document.getElementsByTagName('select');
    for(var i=0; i < sels.length; i++){
        sels[i].onchange= function(){ //pra se mudar pro desabilitado
            if(this.options[this.selectedIndex].disabled){
                if(this.options.length<=1){
                    this.selectedIndex = -1;
                }else if(this.selectedIndex < this.options.length - 1){
                    this.selectedIndex++;
                }else{
                    this.selectedIndex--;
                }
            }
        }
        if(sels[i].options[sels[i].selectedIndex].disabled){
            //se o selecionado atual é desabilitado chamo o onchange
            sels[i].onchange();
        }    
        for(var j=0; j < sels[i].options.length; j++){ //colocando o estilo
            if(sels[i].options[j].disabled){
                sels[i].options[j].style.color = '#CCC';
            }
        }
    }
}
window.attachEvent("onload", ativaOptionsDisabled)
</script>
<![endif]-->

Update: See other good solutions in comment box above too!

Ok. Now its just call this function in document load

<body onload='ativaOptionsDisabled()'>

33 comments:

  1. Nice workaround, but the conditional comment around the function is incorrect.

    The 'disabled' attribute does not work in IE7 either (e.g. its still broken)

    thus the logic should be applied to IE7 and below (presuming that MS fixes it in IE8)

    cheers
    steve

    ReplyDelete
  2. Oooo shit. heheh

    Bad IE, bad.
    Thanks steve.
    I'll update now.

    ReplyDelete
  3. I think that you should attach this function inside that conditional part, like:

    START IF IE HERE
    START SCRIPT HERE
    function ativaOptionsDisabled()
    {
    //...
    }

    window.attachEvent('onload',ativaOptionsDisabled);
    END OF SCRIPT HERE
    END OF IF IE

    What do you think? Now other browsers won't complain about missing function..

    -Cursed

    ReplyDelete
  4. Thanks for the great workaround! I changed the function to the following in order to be more robust. Also, it fixes the assumption that the next option is not disabled:

    if(this.options[this.selectedIndex].disabled){
    var initial_index = this.selectedIndex
    var found = false
    while (this.selectedIndex < this.options.length - 1) {
    this.selectedIndex++
    if (!this.options[this.selectedIndex].disabled) {
    found = true
    break
    }
    }
    if (!found) {
    this.selectedIndex = initial_index
    while (this.selectedIndex > 0) {
    this.selectedIndex--
    if (!this.options[this.selectedIndex].disabled) {
    found = true
    break
    }
    }
    }
    if (!found)
    this.selectedIndex = -1
    }

    ReplyDelete
  5. Great article, thanks a lot.
    But there's a little problem. For example, a select has 3 options: A, B and C. A is disabled. When users select C and then try to select A, B becomes selected.
    Here's my workaround:
    if (this.options[this.selectedIndex].disabled){
    if (this.previousSelectedIndex !== undefined && !this.options[this.previousSelectedIndex].disabled) {
    this.selectedIndex = this.previousSelectedIndex
    } else {
    var initial_index = this.selectedIndex
    var found = false
    while (this.selectedIndex < this.options.length - 1) {
    this.selectedIndex++
    if (!this.options[this.selectedIndex].disabled) {
    found = true
    break
    }
    }
    if (!found) {
    this.selectedIndex = initial_index
    while (this.selectedIndex > 0) {
    this.selectedIndex--
    if (!this.options[this.selectedIndex].disabled) {
    found = true
    break
    }
    }
    }
    if (!found)
    this.selectedIndex = -1
    }
    }
    }
    this.previousSelectedIndex = this.selectedIndex

    ReplyDelete
  6. So with the contribution on October 24, 2007 7:44 AM, what is the final JS funciton?

    Thank you.

    ReplyDelete
  7. Another workaround is to use optgroup for disabled options. Thats ok if they are permanently disabled.

    ReplyDelete
  8. I'd like to suggest you my workaround.
    I had to disable those options dynamically + I'm already using onchange. Therefore I did this:

    1. I had a variable for our fixIE function on the page start + enable/disable functions:

    SCRIPT START

    var fixIEFunction = function(object){return true;}; //this is a fuction for non-ie: it doesn't a thing

    function disableElement(object) {
    object.disabled = true;
    object.style.color = "#CCC";
    }

    function enableElement(object) {
    object.disabled = false;
    object.style.color = "#000";
    }

    SCRIPT END

    2. I placed our fixIE script at the end of the page:

    --OUR IE CHECK--
    SCRIPT START
    fixIEFunction = function fixIEOnChange(object) {
    if(object.options[object.selectedIndex].disabled && (object.oldValue!=null && object.oldValue!=undefined)){
    object.selectedIndex = object.oldValue;
    return false;
    }
    object.oldValue = object.selectedIndex;
    return true;
    }
    SCRIPT END
    --END IE CHECK--

    In this script i override the function to act for IE.

    3. Now we have to initialize our select.oldValue inside body.onload or whenever you want it to be. (You can do this someway else and also use those counting cyclic functions suggested before - but IE is also pretty slow with JS, so using property is faster).

    for all selects on the page just do this:

    select.oldValue = select.selectedIndex;


    4. just run our function inside onChange handler:
    function onChangeHandler(owner) {
    if(fixIEFunction(owner)) {
    //do something useful here
    }
    }

    ReplyDelete
  9. I want to put in another plug for Andreas Øverland's suggestion, the optgroup tag, which I initially overlooked. I never heard of the tag myself until today, and it might be the best workaround for some.

    <optgroup label="some text" > < optgroup >

    It's intended to let your group options in a drop-down menu, like so.

    < optgroup label="sandwiches" >
    < option >PB&J</option >
    < option >BLT</option >
    </ optgroup >

    To simulate a disabled option tag, don't put any options between the opening and closing optgroup tags. Use CSS if you want gray text.

    Here are some links for more.

    http://www.inquirium.net/blog/entry_157.php

    http://reference.sitepoint.com/html/optgroup

    http://msdn.microsoft.com/en-us/library/ms535876(VS.85).aspx

    http://www.w3schools.com/tags/tag_optgroup.asp

    And if this link wasn't posted for a javascript solution...

    http://www.lattimore.id.au/2005/07/01/select-option-disabled-and-the-javascript-solution/

    ReplyDelete
  10. had some cut off links in my post above...Here are sniprurl versions.

    http://snipurl.com/2g797
    Select, Option, Disabled And The JavaScript Solution « Post Archive « www.lattimore.id.au [www_lattimore_id_au]

    http://snipurl.com/2g7a5
    optGroup Object [msdn_microsoft_com]

    ReplyDelete
  11. Thanks very much! Saved my bacon in a crisis!

    ReplyDelete
  12. Hi all...
    I used this posted code in this page in my application and... when I chose only one item of combobox automatically its changed to other item not disabled near the item what I chose. OK. But before I have for example 3 or 4 items disabled near one of another its permitted select one item disabled again?!?! the code what I am posting work fine:
    function conserta() {

    if (document.getElementsByTagName) {

    var s = document.getElementsByTagName("select");

    if (s.length > 0) {

    window.select_current = new Array();

    for (var i=0, select; select = s[i]; i++) {
    select.onfocus = function(){ window.select_current[this.id] = this.selectedIndex; }
    select.onchange = function(){ restore(this); }
    emulate(select);
    }
    }
    }
    }

    function restore(e) {

    if (e.options[e.selectedIndex].disabled) {
    e.selectedIndex = window.select_current[e.id];
    }
    }

    function emulate(e) {

    for (var i=0, option; option = e.options[i]; i++) {

    if (option.disabled) {
    option.style.color = "graytext";
    }
    else {
    option.style.color = "menutext";
    }
    }

    }

    in body put conserta() in onload onption

    (sorry about my bad english)

    hugs...

    ReplyDelete
  13. Thanks.... updated it a little bit and it works like a charm. :)

    ReplyDelete
  14. Minimal changes, works like a charm...

    Use within the IE-checks ofcourse.

    -----------------------------------

    function ativaOptionsDisabled(){
    var sels = document.getElementsByTagName('select');
    for(var i=0; i < sels.length; i++){
    sels[i].onchange= function(){ //pra se mudar pro desabilitado
    if(this.options[this.selectedIndex].disabled){
    if(this.options.length<=1){
    this.selectedIndex = -1;
    }else if(this.selectedIndex < this.options.length - 1){
    do {
    this.selectedIndex++;
    } while(this.options[this.selectedIndex].disabled && this.selectedIndex < (this.options.length-1));
    if(this.options[this.selectedIndex].disabled) {
    do {
    this.selectedIndex--;
    } while(this.options[this.selectedIndex].disabled && this.selectedIndex > -2);
    }
    }else{
    do {
    this.selectedIndex--;
    } while(this.options[this.selectedIndex].disabled && this.selectedIndex > -2);
    }
    }
    }
    if(sels[i].options[sels[i].selectedIndex].disabled){
    //se o selecionado atual é desabilitado chamo o onchange
    sels[i].onchange();
    }
    for(var j=0; j < sels[i].options.length; j++){ //colocando o estilo
    if(sels[i].options[j].disabled){
    sels[i].options[j].style.color = '#CCC';
    }
    }
    }
    }
    window.attachEvent("onload", ativaOptionsDisabled)

    ReplyDelete
  15. Major κῦδος to Micox and Dr4g0nF1y for the help! :^)

    ReplyDelete
  16. Hi,
    this IE bug really troubled me and that code above didn't work on me. I don't know why.

    But then I made a small easy code which removes all non-selected and "disabled" options everytime user loads the page with IE. In other words, there is only one option to choose, the originally selected one.

    Works like a charm now :)

    ReplyDelete
  17. Hey there!
    Nice work!
    But I've git a problem.
    I have three select boxes.
    Your JavaScript only works with the first one.
    What can I do?
    Are you able to extend the script?

    Maybe you can write a mail...
    lukas.liebig@web.de

    Thank you!

    Bye, Lukas

    ReplyDelete
  18. Found a problem. If I have multiple disabled options in a row, it won't just to the next available option, but instead the one directly below it, which is supposed to be disabled.

    ReplyDelete
  19. Thank you this is very usefull.

    ReplyDelete
  20. just tell my visitor not to use IE...

    IE.. make me crazy...
    wasting my time.. and money

    hahhaa

    thanks for the article anyway.. :)

    ReplyDelete
  21. Usando este código não funciona o onchange que tenho no select. Porque será ?

    ReplyDelete
  22. Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!

    ReplyDelete
  23. Amiable dispatch and this enter helped me alot in my college assignement. Gratefulness you as your information.

    ReplyDelete
  24. Opulently I acquiesce in but I contemplate the brief should prepare more info then it has.

    ReplyDelete
  25. Nice dispatch and this post helped me alot in my college assignement. Thank you as your information.

    ReplyDelete
  26. Wow, that all seems like an awful lot of code.

    Wouldn't it be simpler to just check for the disabled attribute, and if it returns true, send a return false? Like this.

    select.onmousedown = function() {
    var index = select.selectedIndex;
    var option = select.options[index];
    if(option.disabled==true) {return false;}
    }

    *lightning meta-CMS

    ReplyDelete
  27. Yes. You are correct.
    Thanks for contribution. :)
    I'll use your solution.

    ReplyDelete
  28. Great stuff, thanks for posting this. IE7 will hopefully be dead soon.

    ReplyDelete
  29. If you know that you only have one item selected, get the 'select' element and pass it into the function below:

    function hideUnSelectedOptions(select)
    {
    var opts = select.options;
    if (select != null)
    {
    while(opts.length > 1)
    {
    for (var i=0; i < opts.length; i++)
    {
    if(opts[i].selected == true)
    {
    opts[i].innerText;
    }
    else
    {
    opts[i] = null;
    break;
    }
    }
    }
    }
    }

    ReplyDelete