JavaScript | ゼロからはじめるプログラミング、30日で基礎を学ぶJavaScript:Webページを操作できるようになる - Day18.5:フォーム操作②

JavaScript JavaScript
スポンサーリンク

Day18.5 後半のゴール

前半で、チェックボックスとラジオボタンの「基本の触り方」は掴めました。
後半ではそれを一歩進めて、実際のフォームらしく

チェックされていないと送信させない
ラジオボタンが未選択ならエラーにする
見た目(エラー表示)と組み合わせる
入力チェックと一緒に設計する

というところまで持っていきます。


チェックボックスを「必須同意」に使う

利用規約に同意していないと送信させない

Webサービスでよくあるのが「利用規約に同意するチェックが必須」というパターンです。

<p>会員登録を行うには、利用規約に同意してください。</p>
<label>
  <input id="termsCheckbox" type="checkbox">
  利用規約に同意します
</label>
<p>
  <button id="submitButton">登録</button>
</p>
<p id="message"></p>

JavaScript で「チェックされていないとエラーにする」処理を書きます。

const termsCheckbox = document.getElementById("termsCheckbox");
const submitButton = document.getElementById("submitButton");
const message = document.getElementById("message");

submitButton.addEventListener("click", () => {
  const agreed = termsCheckbox.checked;

  if (!agreed) {
    message.textContent = "登録するには利用規約に同意してください。";
    return;
  }

  message.textContent = "登録処理を進めます。";
});
JavaScript

ここでの重要ポイントは、
「チェックされているかどうか」を value ではなく checked で判定していることです。
if (!agreed) は「false(=チェックされていない)なら」という意味になります。


エラー時にチェックボックスを強調表示する

classList と組み合わせて「ここが問題」と伝える

メッセージだけだと、どこが悪いのか分かりづらいので、
チェックボックスのラベルを赤くしてみます。

<style>
  .error {
    color: red;
    font-weight: bold;
  }
</style>

<label id="termsLabel">
  <input id="termsCheckbox" type="checkbox">
  利用規約に同意します
</label>
<button id="submitButton">登録</button>
<p id="message"></p>
const termsCheckbox = document.getElementById("termsCheckbox");
const termsLabel = document.getElementById("termsLabel");
const submitButton = document.getElementById("submitButton");
const message = document.getElementById("message");

submitButton.addEventListener("click", () => {
  const agreed = termsCheckbox.checked;

  termsLabel.classList.remove("error");
  message.textContent = "";

  if (!agreed) {
    termsLabel.classList.add("error");
    message.textContent = "利用規約への同意が必要です。";
    return;
  }

  message.textContent = "登録処理を進めます。";
});
JavaScript

毎回最初に classList.remove("error") してから、
今回エラーのときだけ add するのがきれいなパターンです。
「どこを直せばいいか」を視覚的に伝えられるようになります。


ラジオボタンを「必須選択」にする

未選択ならエラーにする基本パターン

ラジオボタンは「必ずどれか1つ選んでほしい」場面が多いです。

<p>支払い方法を選択してください</p>
<label><input type="radio" name="payment" value="card"> クレジットカード</label>
<label><input type="radio" name="payment" value="bank"> 銀行振込</label>
<label><input type="radio" name="payment" value="cash"> 現金</label>

<p>
  <button id="submitButton">決定</button>
</p>
<p id="message"></p>

JavaScript で「未選択ならエラー」を書きます。

const submitButton = document.getElementById("submitButton");
const message = document.getElementById("message");

submitButton.addEventListener("click", () => {
  const selectedRadio = document.querySelector('input[name="payment"]:checked');

  if (selectedRadio === null) {
    message.textContent = "支払い方法を選択してください。";
    return;
  }

  const value = selectedRadio.value;
  message.textContent = `選択された支払い方法:${value}`;
});
JavaScript

ここでのキモは querySelector('input[name="payment"]:checked') です。
「payment グループの中で、checked なものだけ」を一発で取ってきます。
見つからなければ null なので、それを使って未選択を判定します。


ラジオボタンのエラー表示を見た目に反映する

グループ全体を囲って強調する

ラジオボタンは複数の input で1つの意味を持つので、
「グループ全体」を囲ってエラー表示するのが分かりやすいです。

<style>
  .error-box {
    border: 2px solid red;
    padding: 8px;
    background-color: #ffecec;
  }
</style>

<div id="paymentGroup">
  <p>支払い方法を選択してください</p>
  <label><input type="radio" name="payment" value="card"> クレジットカード</label>
  <label><input type="radio" name="payment" value="bank"> 銀行振込</label>
  <label><input type="radio" name="payment" value="cash"> 現金</label>
</div>

<p>
  <button id="submitButton">決定</button>
</p>
<p id="message"></p>
const paymentGroup = document.getElementById("paymentGroup");
const submitButton = document.getElementById("submitButton");
const message = document.getElementById("message");

submitButton.addEventListener("click", () => {
  const selectedRadio = document.querySelector('input[name="payment"]:checked');

  paymentGroup.classList.remove("error-box");
  message.textContent = "";

  if (selectedRadio === null) {
    paymentGroup.classList.add("error-box");
    message.textContent = "支払い方法を選択してください。";
    return;
  }

  message.textContent = `選択された支払い方法:${selectedRadio.value}`;
});
JavaScript

ラジオボタンは「どれか1つ」なので、
個々の input にエラーを付けるより、
グループ全体を囲って「ここが未選択だよ」と示す方が親切です。


チェックボックスとラジオボタンを組み合わせた入力チェック

「同意」と「選択」を同時に満たさないと進めないフォーム

少しだけ複雑な例として、
「利用規約に同意」+「連絡方法を選択」の両方が必須のフォームを考えます。

<h2>連絡設定</h2>

<label id="termsLabel">
  <input id="termsCheckbox" type="checkbox">
  利用規約に同意します
</label>

<div id="contactGroup">
  <p>希望する連絡方法を選択してください</p>
  <label><input type="radio" name="contact" value="email"> メール</label>
  <label><input type="radio" name="contact" value="phone"> 電話</label>
  <label><input type="radio" name="contact" value="none"> 連絡不要</label>
</div>

<p>
  <button id="submitButton">設定を保存</button>
</p>
<p id="message"></p>
const termsCheckbox = document.getElementById("termsCheckbox");
const termsLabel = document.getElementById("termsLabel");
const contactGroup = document.getElementById("contactGroup");
const submitButton = document.getElementById("submitButton");
const message = document.getElementById("message");

submitButton.addEventListener("click", () => {
  const agreed = termsCheckbox.checked;
  const selectedContact = document.querySelector('input[name="contact"]:checked');

  termsLabel.classList.remove("error");
  contactGroup.classList.remove("error-box");
  message.textContent = "";

  let hasError = false;
  let messages = [];

  if (!agreed) {
    hasError = true;
    messages.push("利用規約に同意してください。");
    termsLabel.classList.add("error");
  }

  if (selectedContact === null) {
    hasError = true;
    messages.push("連絡方法を選択してください。");
    contactGroup.classList.add("error-box");
  }

  if (hasError) {
    message.textContent = messages.join(" ");
    return;
  }

  message.textContent = "設定を保存しました。";
});
JavaScript

ここでやっていることは、Day19 以降の「入力チェック」と同じ構造です。

チェックボックス:checked で必須同意を判定
ラジオボタン:querySelector で選択済みか判定
エラーがあればフラグとメッセージで管理し、最後にまとめて表示
classList で「どこが問題か」を見た目に反映

チェックボックスとラジオボタンも、
結局は「条件+DOM」の一部として扱える、という感覚を持ってほしいところです。


セキュリティの視点から見たチェックボックス・ラジオボタン

「フロントの状態は信用しすぎない」

チェックボックスやラジオボタンの状態も、
ブラウザ側ではユーザーが自由に書き換えられます。

開発者ツールで HTML をいじる
JavaScript コンソールから checked を変更する

こういったことができてしまうので、
本番のサービスでは必ずサーバー側でも

利用規約に同意しているか
必須の選択がされているか

を再チェックします。

ただし、フロント側でのチェックには

ユーザーのミスをその場で気づかせる
明らかにおかしい状態のリクエストを減らす

という大きな意味があります。
そして、画面に表示するメッセージには必ず textContent を使うことで、
ユーザー入力を HTML として解釈してしまう危険(XSS)を避けられます。


Day18.5 後半のミニ総合サンプル

「同意+選択」を伴う小さな設定フォーム

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Day18.5 フォーム操作② 後半</title>
    <style>
      .error {
        color: red;
        font-weight: bold;
      }
      .error-box {
        border: 2px solid red;
        padding: 8px;
        background-color: #ffecec;
      }
      .message {
        font-size: 14px;
      }
    </style>
  </head>
  <body>
    <h1>通知設定</h1>

    <h2>利用規約</h2>
    <label id="termsLabel">
      <input id="termsCheckbox" type="checkbox">
      利用規約に同意します
    </label>

    <h2>通知方法</h2>
    <div id="notifyGroup">
      <p>通知を受け取る方法を選択してください</p>
      <label><input type="radio" name="notify" value="email"> メール</label>
      <label><input type="radio" name="notify" value="sms"> SMS</label>
      <label><input type="radio" name="notify" value="none"> 通知不要</label>
    </div>

    <p>
      <button id="saveButton">設定を保存</button>
    </p>

    <p id="message" class="message"></p>

    <script>
      const termsCheckbox = document.getElementById("termsCheckbox");
      const termsLabel = document.getElementById("termsLabel");
      const notifyGroup = document.getElementById("notifyGroup");
      const saveButton = document.getElementById("saveButton");
      const message = document.getElementById("message");

      saveButton.addEventListener("click", () => {
        const agreed = termsCheckbox.checked;
        const selectedNotify = document.querySelector('input[name="notify"]:checked');

        termsLabel.classList.remove("error");
        notifyGroup.classList.remove("error-box");
        message.textContent = "";

        let hasError = false;
        const messages = [];

        if (!agreed) {
          hasError = true;
          messages.push("利用規約に同意してください。");
          termsLabel.classList.add("error");
        }

        if (selectedNotify === null) {
          hasError = true;
          messages.push("通知方法を選択してください。");
          notifyGroup.classList.add("error-box");
        }

        if (hasError) {
          message.textContent = messages.join(" ");
          return;
        }

        message.textContent = "設定を保存しました。";
      });
    </script>
  </body>
</html>

チェックボックスとラジオボタンが、
単なる「入力パーツ」ではなく、
「条件+DOM+入力チェック」の一部として動いているのが分かると思います。


Day18.5 後半のまとめ

後半では、チェックボックスとラジオボタンを

必須同意(利用規約)
必須選択(支払い方法・連絡方法)
エラー表示(classList で見た目を変える)
入力チェックの流れの中に組み込む

という形で、フォームらしい使い方にまで持っていきました。

ここまで理解できていれば、
「ただ値を取る」段階から一歩進んで、
「ユーザーの状態を条件として扱う」フォーム設計ができるようになっています。

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