Friday, May 29, 2009

JQuery, IE6, and 'Could not set the selected property. Unspecified error.'

I was trying to do this with JQuery - imagine htmlOptions is a client-side cache of option values to put in a select box, ctrl is the id of the box, and id is the current selected value:


function loadDropDown(htmlOptions, ctrl, id) {
   $(ctrl).html(htmlOptions); 
   $(ctrl).val(id); 
}

It worked great on everything but IE 6.0. Then I got the big, fat "Could not set the selected property. Unspecified error." Turns out there is a little bit of a timing issue with the DOM. After scouring the 'net for solutions, I finally settled on this as my favorite - no crazy browser hacks to determine the type and version, IE 6.0 gets the short end of the stick as it deserves:


function loadDropDown(htmlOptions, ctrl, id) {
   $(ctrl).html(htmlOptions); 
   try {
      $(ctrl).val(id); 
   }
   catch(ex) {
      setTimeout("$('" + ctrl + "').val('" + id + "')",1); 
   }
}

It's just enough delay to let the DOM settle and not complain.

Jeremy Likness

18 comments:

  1. Good Stuff! I had a similar bug and found this post via google search. Saved the day for me. Thanks :)

    ReplyDelete
  2. Hey, this saved my day (well, rather my evening) as well :) Thanks!

    ReplyDelete
  3. Thanks!! I am happy to see I was not the only one with this bug.

    ReplyDelete
  4. Wow I never would have guessed at this issue. Nice work finding the fix works a treat.

    ReplyDelete
  5. Hey Thank you very much. That saved lot of time. Really helped a lot.

    ReplyDelete
  6. thanks. This helped me out as well. My problem was a little bit different:
    MyJqueryObj.attr('selected','selected'); was giving me the error.

    to fix it, I put the command in a try block and had a catch block with nothing in it. With this change, the option was selected correctly and I didn't get an error.

    ReplyDelete
  7. Thank you very mush! I lost one day, finding solving of this problem.

    ReplyDelete
  8. Nice, simple, workaround, thanks.

    I'd suggest a couple of minor improvements.

    (a) in most cases, there's no need for the first line; you may as well *always* do a setTimeout. It will delay the change by 1 millisecond in modern browsers, but it keeps your code smaller.

    (b) a closure instead of constructing the string:
    setTimeout(function() { $ctl.val(id); }, 1);

    ReplyDelete
  9. Thanks a ton,
    This helps. I faced the similar thing and I commented out the JS code that selects the value after updating DOM tree and it worked. Do you have any link for other solutions though?
    Note: I will link to your article from my blog as well for my future reference. I hope that is okay.
    Regards,
    Amit

    ReplyDelete
  10. //i'm mibany
    //backup
    jQuery.fn._change = jQuery.fn.change;
    //override
    jQuery.fn.change = function(fn){
    //IE && Version 6.0 == IE6
    if($.browser.msie && $.browser.version == "6.0") {
    $(this).get(0).onchange = function() {
    eval(fn());
    }
    return $(this);
    }
    //exec old function
    return $(this)._change(fn);
    };

    ReplyDelete
  11. I struggled with this for 4 hours, also tried delays, but nothing helped (i had a page with multiple dynamic option boxes) in the end i just reversed my jQuery code to good oldschool javascript and was ok.

    ReplyDelete
  12. Thanks Buddy .... i strugged for a day ...
    then your solution ...it works :)

    thanks a lot for your help

    ReplyDelete
  13. This is exactly what I am looking for!! thanks!

    ReplyDelete
  14. Thanks man! works like a dream

    ReplyDelete
  15. Yeah, it's perfect. It worked better with the Michael Mahemoff's answer. Thanks to all.

    ReplyDelete
  16. Thank you for your solution, seems to work great!
    IE6 can be frustrating...

    ReplyDelete
  17. Hi i was trying to this query with javascript, It has working will in all the browser but not working in IE 6.0 so please help me....

    function setSelectedIndex(s, v) {
    for (var i = 0; i < s.options.length; i++) {
    if (s.options[i].text == v) {
    s.options[i].selected = true;
    return;
    }
    }
    }

    ReplyDelete