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 で見た目を変える)
入力チェックの流れの中に組み込む
という形で、フォームらしい使い方にまで持っていきました。
ここまで理解できていれば、
「ただ値を取る」段階から一歩進んで、
「ユーザーの状態を条件として扱う」フォーム設計ができるようになっています。
