JavaScript | DOM 操作:フォーム操作 – select の取得・変更

JavaScript JavaScript
スポンサーリンク

select の取得・変更とは何か

select は「選択肢の中から値を1つ(または複数)選ぶ」ためのフォーム要素です。JavaScript では現在の選択値を読み取ったり、選択を変更したり、選択肢を動的に追加・削除できます。ここが重要です:単一選択(single)と複数選択(multiple)で取得方法が少し違います。送信(FormData)でどう展開されるかも理解しておくと、データの取り扱いが正確になります。


現在の選択を正しく取得する

単一選択(single)の基本

<select id="country">
  <option value="">選択してください</option>
  <option value="JP">日本</option>
  <option value="US">アメリカ</option>
</select>
<script>
  console.log(country.value);         // 例: "JP"
  console.log(country.selectedIndex); // 例: 1(0はプレースホルダー)
  console.log(country.options[country.selectedIndex].text); // ラベル文字列
</script>
HTML

ここが重要です:value は「送る値」、text はユーザーに見えるラベル。selectedIndex が -1 のときは未選択で、value は通常空文字になります。必須入力にしたい場合、先頭に value=”” の無効オプションを置くのが定番です。

複数選択(multiple)の基本

<select id="tags" multiple size="4">
  <option value="js">JavaScript</option>
  <option value="css">CSS</option>
  <option value="html">HTML</option>
  <option value="ui">UI/UX</option>
</select>
<script>
  const values = [...tags.selectedOptions].map(o => o.value);
  console.log(values); // 例: ["js", "ui"]
</script>
HTML

ここが重要です:multiple の select は「選ばれている複数」を selectedOptions から配列化して扱います。単一用の value プロパティは先頭の選択だけを返すため、複数選択では使いません。


選択状態をプログラムで変更する

value で直接変更する(単一選択)

<script>
  country.value = "US";              // US を選択状態にする
  // 見つからない値を指定すると選択は外れる(selectedIndex が -1)
</script>
HTML

ここが重要です:value 変更は最短で確実。指定値が存在しないと未選択になるため、必ず存在チェックを入れるか、fallback を用意します。

selectedIndex や option.selected を使う

<script>
  country.selectedIndex = 2;         // 3番目の option(0始まり)
  country.options[1].selected = true; // 2番目を選択
</script>
HTML

ここが重要です:DOM の並びで選びたいときは selectedIndex。複数選択では各 option.selected を true/false で切り替えれば、複数を同時に選べます。

複数選択をまとめてセット

<script>
  function setMultiple(select, values) {
    for (const opt of select.options) opt.selected = values.includes(opt.value);
  }
  setMultiple(tags, ["css", "ui"]);
</script>
HTML

ここが重要です:multiple は「全部の option に対して selected を決める」考え方にすると、状態がズレません。

変更イベントの発火に注意する

<script>
  country.addEventListener("change", () => console.log("ユーザー確定:", country.value));

  country.value = "JP"; // これだけでは "change" は発火しないブラウザが多い
  country.dispatchEvent(new Event("change", { bubbles: true })); // 明示発火
</script>
HTML

ここが重要です:プログラム変更で処理を走らせたい場合は、イベントを自分で dispatch します。ユーザー操作に反応したいだけなら change リスナーで十分です。


option の追加・削除・置換(動的に選択肢を操作する)

追加(new Option と add)

<select id="city"></select>
<script>
  city.add(new Option("東京", "TOK"));     // 末尾に追加
  city.add(new Option("大阪", "OSA"), 0); // 先頭に挿入(インデックス指定)
</script>
HTML

ここが重要です:new Option(text, value) は簡潔で可読性が高い追加方法です。第二引数の位置指定で並びを制御できます。

削除(remove と length)

<script>
  city.remove(1);   // 2番目の option を削除
  city.length = 0;  // 全削除(空にする)
</script>
HTML

ここが重要です:length=0 は「一括クリア」。再構築前に必ずクリアしてから追加すると、重複や古い選択の混在を防げます。

置換(安全な再構築)

<script>
  function replaceOptions(select, items) {
    select.length = 0; // クリア
    for (const { text, value, selected } of items) {
      const opt = new Option(text, value, selected === true, selected === true);
      select.add(opt);
    }
  }
  replaceOptions(city, [
    { text: "札幌", value: "SPK" },
    { text: "名古屋", value: "NGY", selected: true },
  ]);
</script>
HTML

ここが重要です:一度空にしてから「必要な選択肢だけを明示的に追加する」手順が安全です。selected の初期指定もここで行えます。


FormData と送信時の値(single と multiple の違い)

単一選択は get、複数選択は getAll

<form id="f">
  <select name="tag" multiple>
    <option value="js" selected>JavaScript</option>
    <option value="css">CSS</option>
    <option value="ui" selected>UI/UX</option>
  </select>
</form>
<script>
  const fd = new FormData(f);
  console.log(fd.get("tag"));      // "js"(先頭だけ)
  console.log(fd.getAll("tag"));   // ["js", "ui"](複数すべて)
</script>
HTML

ここが重要です:multiple は get だと「先頭だけ」。送信相当の全値が欲しいときは必ず getAll を使います。単一選択なら get で十分です。

未選択・無効オプションの扱い

<select id="role" name="role">
  <option value="" disabled selected>選択してください</option>
  <option value="admin">管理者</option>
</select>
<script>
  const fd = new FormData(document.querySelector("form"));
  // disabled の option は送信対象外。空文字の選択は実質「未選択」扱いにする設計が安全
</script>
HTML

ここが重要です:disabled な option は送信されません。先頭プレースホルダーは disabled+selected+value=”” にすると、未選択状態を明確化できます。


実践例で学ぶ(依存セレクト、表示同期、非同期ロード)

都道府県→市区町村の依存セレクト

<select id="pref">
  <option value="">都道府県</option>
  <option value="tokyo">東京都</option>
  <option value="osaka">大阪府</option>
</select>
<select id="ward"></select>
<script>
  const WARDS = {
    tokyo: [{ text: "江東区", value: "koto" }, { text: "渋谷区", value: "shibuya" }],
    osaka: [{ text: "北区", value: "kita" }, { text: "中央区", value: "chuo" }],
  };
  function fill(select, items) {
    select.length = 0;
    for (const i of items) select.add(new Option(i.text, i.value));
    if (items.length === 0) select.add(new Option("選択なし", "", true, true));
  }
  pref.addEventListener("change", () => fill(ward, WARDS[pref.value] || []));
  fill(ward, []); // 初期は空
</script>
HTML

ここが重要です:親の選択に応じて子を再構築するときは、必ず「クリア→追加」の順にし、未選択状態を明示的に作っておくと UX が安定します。

選択に応じて表示を同期する

<select id="country">
  <option value="JP">日本</option>
  <option value="US">アメリカ</option>
</select>
<div id="summary"></div>
<script>
  function sync() {
    const opt = country.options[country.selectedIndex];
    summary.textContent = `選択: ${opt.text}(値: ${opt.value})`;
  }
  country.addEventListener("change", sync);
  sync();
</script>
HTML

ここが重要です:UI の別要素に選択内容を反映する場合、change で同期するだけで十分です。初期表示も忘れずに一度同期します。

非同期で選択肢をロードする

<select id="city"></select>
<script>
  async function loadCities() {
    city.length = 0;
    city.add(new Option("読み込み中...", "", true, true));
    const res = await fetch("/api/cities");
    const list = await res.json(); // [{text, value}]
    city.length = 0;
    for (const i of list) city.add(new Option(i.text, i.value));
  }
  loadCities();
</script>
HTML

ここが重要です:非同期ロードでは「仮の選択肢」を先に入れて状態を示し、完了後に本物へ置き換えます。中断・失敗時の扱い(再試行、エラーメッセージ)も設計しておくと親切です。


よくある落とし穴と回避策

値とラベルの混同は典型的なバグの元です。ユーザーに見せる文字は option.text、送る値は option.value。複数選択で単一用の value を読むと先頭しか取れず、意図通り送れません。必ず selectedOptions と FormData.getAll を使います。プログラムで選択を変えても change が発火しないことがあるため、必要なら dispatchEvent で明示的に通知します。name がない select は FormData に含まれないため、送信対象なら必ず name を付けます。存在しない値を設定すると未選択になるので、データ→UI の反映時には値が正しいか検証し、見つからない場合のフォールバック(先頭に戻すなど)を用意してください。


まとめ

select の取得・変更は「単一と複数で取り方を分ける」が最重要ポイントです。単一は value/selectedIndex、複数は selectedOptions を配列化して扱い、送信相当の値は FormData.get(単一)と getAll(複数)で正確に取り出します。選択肢の動的操作は「クリア→追加→初期選択」の順序を守るとズレません。プログラム変更でイベントを必要とする場合は dispatchEvent で明示通知。値とラベル、単一と複数、表示と送信の基準を整理すれば、初心者でも読みやすく壊れにくいセレクト操作が書けます。

タイトルとURLをコピーしました