jQueryのIE6のバグを報告したら有名なIE6のバグと言われた件

個人的にはIE6なんてもう対応する気もないんだけど、そういう分けにもいかずハマったので、検証コードを書いてみた。それでも再現するので、これはjQueryのバグかと思い報告してみたら(closed bug: cantfix)を頂きました。

This is a well-known issue with IE6 being unable to update options, and can be fixed with setTimeout or one of the solutions suggested in the links below:

#11564 ($('option').attr('selected', true) does not work on IE6) – jQuery - Bug Tracker

well-known issueという事で、割と知られてるIE6のバグ?みたい。検証コードでも再現したからといって、すぐにバグ報告しないでフォーラムにまず書くべきだったかもなぁ。

ちなみに、ブログに書くのがおっくうで、報告したのはもう3ヶ月も前みたいです。

内容

jQuery+IE6の組み合わせで、JavaScriptエラーが発生します。

<form id="foo">
    <select name="foo">
    </select>
    <button>run</button>
</form>
http://jsfiddle.net/dmethvin/SVTUm/

option要素はjQueryで組み立てるつもりで、option要素を持たないselect要素をhtmlに書いてます。

$(function(){
    $('button').click(function(e){
        e.preventDefault();
        var $select = $(this.form).find("select").empty();
        var array = ['ein', 'zwei', 'drei'];
        for( var i=0; i<array.length; i++ ){
            var $option = $('<option>');
            $option.val('').text(array[i]);
            $select.prepend($option);
        }
        $select.children(':first').prop('selected', true);
    });
});&#8203;
http://jsfiddle.net/dmethvin/SVTUm/

そしてjQueryでoption要素をいくつか追加し、どれかをselectedにしようとすると・・・IE6限定でJavaScriptエラーが発生します。>=IE7*1やその他のモダンブラウザでは発生してません。

解決方法

$(function(){
    $('button').click(function(e){
        e.preventDefault();
        var $select = $(this.form).find("select").empty();
        var array = ['ein', 'zwei', 'drei'];
        for( var i=0; i<array.length; i++ ){
            var $option = $('<option>');
            $option.val('').text(array[i]);
            $select.prepend($option);
        }
        setTimeout( function() {
          $select.children(':first').prop('selected', true);
        }, 1);
    });
});&#8203;
http://jsfiddle.net/dmethvin/SVTUm/1/

setTimeout()で非同期処理にすると回避できるようです。

Because it is a timing issue it can't be fixed within jQuery core without introducing even more issues (e.g., what if other things run before we select the option in the timeout?)

#11564 ($('option').attr('selected', true) does not work on IE6) – jQuery - Bug Tracker

英文読解力が足りずに、意図を完全に汲み取れてないんですが、これはタイミングの問題らしい。提示されたstack over flowも読んでみると、JavaScriptで生成した要素にJavaScriptがアクセスする場合の、生成とアクセスのタイミングの事を言ってるような気がしました。

補足
<form id="bar">
    <select name="bar">
    <option value="">dummy</option>
    </select>
    <button>run</button>
</form>&#8203;
http://jsfiddle.net/dmethvin/SVTUm/

option要素を最初から入れておけば、たとえそれを$().empty()で消して、改めてoption要素を積んだとしても、エラーは発生しませんでした。

jsdo.it

Test case for an error of $('option').attr('selected', true) only on IE6 - jsdo.it - Share JavaScript, HTML5 and CSS

さっきからJSFiddleからばかり貼ってるけど、最初はjsdo.itで検証コード書いてたんだよね。

The site jsdo.it does not work for me in IE6. This JSFiddle reproduces the issue:

#11564 ($('option').attr('selected', true) does not work on IE6) – jQuery - Bug Tracker

jsdo.itって、UI英語にしてるし海外でもそこそこ使われてるのかなーとか思ったんだけど、「動かないからJSFiddleで作りなおした」って言われてしまいました。

http://jsfiddle.net/dmethvin/SVTUm/
http://jsfiddle.net/dmethvin/SVTUm/1/

確かにこのJSFiddleは、Saveする度にURLが発行されて、ちょっとしたバージョン管理みたいな感じになってて便利そう。今回の、動かないコードと、直したコードもスッキリとしてるし。ただ、まちがってSaveしちゃっても、URLのカウントアップは取り消せないみたい。

環境

jQuery 1.7.0 1.7.1 1.7.2*2

*1:IE7とそれ以上

*2:試したのは1.7系だけだけど、cantfixなので全バージョンで発生するんだろうと思う。