jQuery / Selector / :selected — selectで選ばれたoptionを取得する

jQuery :selectedはselect内で現在選ばれたoptionを取得します。$("#fruit option:selected")は要素、$("#fruit").val()は値を読みます。HTMLのselected属性と利用者が変えた現在状態は異なる場合があります。

要素・値・表示名を分ける

:selected公式文書の対象はoptionで、チェックボックスやラジオではありません。対象selectやフォームへ範囲を限定し、他の選択を混ぜません。

optionの.text()は表示名、.val()はvalueです。複数option集合の.val()は最初だけ、.text()は全文字を連結します。複数selectの値全体はselect自身の.val()、要素別情報はmapやeachで扱います。

例は果物一つと複数トピックです。表示JavaScriptと識別子jsを分けます。disabledなoptionとoptgroupで、選択状態と送信可能な値が別であることも比較します。

単一・複数選択の完全な例

UTF-8のselected-demo.htmlで保存し開きます。完全版jQuery4.0.0をネットから読み、サーバーやビルド不要です。Windows Edgeの4.0.0・3.7.1で初期値、キーボード、無効項目、空選択と復帰を確認しました。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Read selected options and submitted values</title>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
  <style>
    body { font: 16px/1.6 sans-serif; max-width: 740px; margin: 20px; }
    label { display: block; margin-top: 12px; }
    select, button { font: inherit; max-width: 100%; margin: 6px 0; }
    #topics { display: block; min-width: 230px; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  </style>
</head>
<body>
  <form id="chooser">
    <label for="fruit">Fruit (single)</label>
    <select id="fruit" name="fruit"><option value="apple">Apple</option><option value="banana">Banana</option></select>
    <label for="topics">Topics (multiple)</label>
    <select id="topics" name="topics" multiple size="6">
      <option value="js" selected>JavaScript</option>
      <option value="css">CSS</option>
      <option value="html" selected disabled>HTML (disabled)</option>
      <optgroup label="Unavailable group" disabled><option value="legacy" selected>Legacy</option></optgroup>
    </select>
    <button type="button" id="set">Set Banana and CSS</button>
    <button type="button" id="clear">Clear topics</button>
    <button type="button" id="restore">Reset</button>
  </form>
  <pre id="result" aria-live="polite"></pre>
  <script>
    jQuery(function ($) {
      const $fruit = $("#fruit"), $topics = $("#topics"), form = document.querySelector("#chooser");
      let changes = 0;
      function values($options) { return $options.map(function () { return this.value; }).get(); }
      function render() {
        const $selected = $topics.find("option").filter(":selected");
        const data = new URLSearchParams(new FormData(form));
        $("#result").text("single=" + $fruit.val() + "\nsingleText=" + $fruit.find("option:selected").text() +
          "\nselectedOptions=" + JSON.stringify(values($selected)) + "\nvalues=" + JSON.stringify($topics.val()) +
          "\nselectedAttribute=" + JSON.stringify(values($topics.find("option[selected]"))) +
          "\nform=" + data.toString() + "\nchanges=" + changes);
      }
      $fruit.add($topics).on("change", function () { changes++; render(); });
      $("#set").on("click", function () {
        $fruit.val("banana").trigger("change"); $topics.val(["css"]).trigger("change");
      });
      $("#clear").on("click", function () { $topics.val([]).trigger("change"); });
      $("#restore").on("click", function () { form.reset(); changes = 0; render(); });
      render();
    });
  </script>
</body>
</html>

Fruitにはselected属性がなくても単一selectの先頭Appleが選ばれます。Topicsの三項目は選択状態ですが送信できる値はjsだけです。

single=apple
singleText=Apple
selectedOptions=["js","html","legacy"]
values=["js"]
selectedAttribute=["js","html","legacy"]
form=fruit=apple&topics=js
changes=0
  1. Bananaへ変えるとsingle=bananaとsingleText=Bananaが変わります。キーボードでもchangeで更新します。
  2. Set Banana and CSSでselectedOptions・valuesは["css"]、selectedAttributeは["js","html","legacy"]のままです。
  3. Clear topicsで前二者は[]となり、formにはfruitだけ残ります。
  4. ResetでHTML・Legacyの無効選択も含め初期状態へ戻ります。
  5. 手動複数選択はOS・ブラウザーのキー操作を使います。ボタンは端末差なく比較するためです。

selectedOptionsはDOM選択値、valuesはselectの.val()、selectedAttributeは属性です。formはFormDataのURLクエリー表現で送信しません。changesは処理回数で、Setは二selectに各一イベントなので2です。

現在状態と既定属性

option.selectedと:selectedは現在状態です。[selected]は属性の有無、defaultSelectedは既定状態に対応します。利用者変更が同じように既定属性を書き換えるわけではないので、現在判定へ[selected]を使いません。

.val(["css"])は現在選択を変え、.val([])は複数選択を消します。.val()の設定はchangeを自動発生しないため例は明示発火します。イベントやrenderがないと報告だけ古いままになることがあります。

jQuery 3以上で未選択の複数selectは[]、空option集合の.val()はundefinedです。単一selectに未知値を設定し選択がなくなるとnullです。全て空文字とは考えません。

Resetはform.reset()後にrenderします。既定属性自体を編集すれば復帰先も変わります。この例は属性を保ち現在値だけ変えているので初期比較へ戻せます。

無効項目・:checked・適用

disabledのoptionや無効optgroup内の選択は:selectedに残ってもselectの.val()とFormDataから除外されます。DOM選択数は送信値数ではありません。初期の三対一がその例です。name欠落やselect全体の無効も送信時に確認します。

:checkedはoptionとチェックボックス・ラジオに対応します。option:checkedへ限定すればこの例で同じですが、全体の:checkedは種類が混ざります。

:selectedはjQuery拡張で標準document.querySelectorAll()へ直接渡せません。例はCSSでoptionを選び.filter(":selected")します。標準コードならselect.selectedOptionsや範囲を限定したoption:checkedを検討します。

色やフィルターへの反映は変更だけでなく初期化時にも一回行います。コードによる設定時の更新経路も決め、表示名はHTML連結でなく.text()を使います。サーバーはvalueと業務条件を再検査します。