IE8以下はvalue属性がないoption要素の値をJavaScriptのvalueプロパティで取得できない

HTMLでselect要素を使った選択肢を記述する場合、出力される文字列と送信される値が同一の場合、option要素のvalue属性が省略できます。HTML4.01仕様書には次のように書かれています。

When rendering a menu choice, user agents should use the value of the label attribute of the OPTION element as the choice. If this attribute is not specified, user agents should use the contents of the OPTION element.

Forms in HTML documents(W3C)

すなわち、<option value="hoge">hoge</option><option>hoge</option> は等価になるはずですが、スクリプトを使用する場合は注意が必要です。

たとえば、次のコードのようにJavaScriptを使って選択済みの値を取得する場合、IE8以下ではvalue属性のないoption要素の値が取得できません。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<title>IE8以下はvalue属性がないoption要素の値をJavaScriptのvalueプロパティで取得できない</title>
<script type="text/javascript">
//<![CDATA[
window.onload = function() {
  var selects = document.getElementsByTagName("select");
  for (var i = 0; i < selects.length; i++) {
    var select = selects[i];

    /* select要素の直後に <span class="value-writing">選択された値: <em>hoge</em></span> という形で要素を挿入する */
    var valueWriting = document.createElement("span");
    valueWriting.setAttribute("class", "value-writing");
    valueWriting.appendChild(document.createTextNode("選択された値: "));
    select.parentNode.insertBefore(valueWriting, select.nextSibling);

    var value = document.createElement("em");
    value.appendChild(document.createTextNode(select.value));
    valueWriting.appendChild(value);

    try {
      select.addEventListener("change", function() {
        // 選択肢を変更した時の処理
        this.nextSibling.getElementsByTagName("em").item(0).textContent = this.value;
      }, false);
    } catch (e) {
      // IE8以下は addEventListener() がないので attachEvent() で代用
      select.attachEvent("onchange", function() {
        event.srcElement.nextSibling.getElementsByTagName("em").item(0).innerText = event.srcElement.value;
      });
    }
  }
};
//]]>
</script>
</head>
<body>
<form action="">
<p>
<select name="foo">
<option value="hoge" selected="selected">hoge (value属性あり)</option>
<option>fuga</option>
</select>
</p>
</form>
</body>
</html>
IE9でvalue属性のない要素を選択した様子
IE8でvalue属性のない要素を選択した様子

これの解決方法は2つ考えられ、ひとつはすべてのoption要素に適切なvalue属性を付けること、あるいはJavaScriptライブラリを利用することで古いIEにも対応できます。

  • 素のJavaScriptでも頑張れば解析できなくはないでしょうが、あまり現実的でなさそうなので除外。

jQueryならば.val()メソッド(api.jquery.com) を使う事で、IE8以下でも値を取得する事ができますね。

jQuery(function($) {
  var sel = $("select").each(function() {
    /* select要素の直後に <span class="value-writing">選択された値: <em>hoge</em></span> という形で要素を挿入する */
    $(this).after($('<span class="value-writing"/>').text("選択された値: ").append($("<em/>").text($(this).val())));

    /* すべてのselect要素にイベントを登録する */
    $(this).change(function() {
      // 選択肢を変更した時の処理
      $(this).next("span").children("em").text($(this).val());
    });
  });
});

スクリプト自体も短くすっきりするので、jQueryが利用できる環境ならばこちらの方がおすすめな感じです。