Day19 後半のゴール
後半では、前半で作った「入力チェックの基本」を、
もう一歩“フォームらしい体験”に近づけます。
複数項目のエラーをまとめて扱う
どの項目がエラーなのかを見た目で伝える
エラーがあるときは「処理を進めない」ことを徹底する
このあたりを、条件分岐+DOM 操作でしっかり形にしていきます。
複数のエラーをまとめて表示する
1つずつ return する書き方の限界
前半では、こんな書き方をしました。
if (name === "") {
messageElement.textContent = "名前を入力してください。";
return;
}
if (ageText === "") {
messageElement.textContent = "年齢を入力してください。";
return;
}
JavaScriptこれは「最初に見つかったエラーだけを表示する」スタイルです。
実務では、「名前も年齢も両方おかしいなら、両方教えてほしい」という場面が多いです。
そこで、「エラーメッセージをためてから、まとめて表示する」パターンにしてみます。
エラーを配列にためるパターン
<input id="nameInput" type="text" placeholder="名前">
<input id="ageInput" type="text" placeholder="年齢">
<button id="submitButton">送信</button>
<p id="message"></p>
const nameInputElement = document.getElementById("nameInput");
const ageInputElement = document.getElementById("ageInput");
const submitButtonElement = document.getElementById("submitButton");
const messageElement = document.getElementById("message");
submitButtonElement.addEventListener("click", () => {
const name = nameInputElement.value.trim();
const ageText = ageInputElement.value.trim();
const errors = [];
if (name === "") {
errors.push("名前を入力してください。");
}
if (ageText === "") {
errors.push("年齢を入力してください。");
} else {
const age = Number(ageText);
if (Number.isNaN(age)) {
errors.push("年齢は数字で入力してください。");
} else if (age <= 0) {
errors.push("年齢は1以上の数で入力してください。");
}
}
if (errors.length > 0) {
messageElement.textContent = errors.join(" ");
return;
}
messageElement.textContent = `${name} さんは ${ageText} 歳ですね。`;
});
JavaScriptここでのポイントは、errors という配列を使っていることです。
エラーが見つかるたびに errors.push(…) で追加する
最後に errors.length を見て、「1つ以上あれば NG」と判定する
errors.join(” “) で、1つの文字列にまとめて表示する
この書き方にすると、
「名前も年齢も両方おかしい」という状況を、1回の送信で全部伝えられます。
どの項目がエラーかを見た目で伝える
エラーの input にだけクラスを付ける
メッセージだけでなく、
「どの入力欄が問題なのか」を見た目で示すと、ユーザー体験が一気に良くなります。
まず CSS でエラー用のクラスを用意します。
<style>
.error {
border: 2px solid red;
background-color: #ffecec;
}
</style>
HTML は先ほどと同じです。
<input id="nameInput" type="text" placeholder="名前">
<input id="ageInput" type="text" placeholder="年齢">
<button id="submitButton">送信</button>
<p id="message"></p>
JavaScript を少し変えます。
submitButtonElement.addEventListener("click", () => {
const name = nameInputElement.value.trim();
const ageText = ageInputElement.value.trim();
const errors = [];
nameInputElement.classList.remove("error");
ageInputElement.classList.remove("error");
if (name === "") {
errors.push("名前を入力してください。");
nameInputElement.classList.add("error");
}
if (ageText === "") {
errors.push("年齢を入力してください。");
ageInputElement.classList.add("error");
} else {
const age = Number(ageText);
if (Number.isNaN(age)) {
errors.push("年齢は数字で入力してください。");
ageInputElement.classList.add("error");
} else if (age <= 0) {
errors.push("年齢は1以上の数で入力してください。");
ageInputElement.classList.add("error");
}
}
if (errors.length > 0) {
messageElement.textContent = errors.join(" ");
return;
}
messageElement.textContent = `${name} さんは ${ageText} 歳ですね。`;
});
JavaScript重要な流れはこうです。
最初に全ての input から error クラスを外す
チェックの中で NG になった input にだけ error クラスを付ける
これで、「どこを直せばいいか」が一目で分かるフォームになります。
条件を関数に切り出して整理する
バリデーションロジックを分離する
チェックが増えてくると、イベントハンドラの中が長くなりがちです。
そこで、「チェックする部分」を関数に切り出してみます。
function validateProfile(name, ageText) {
const errors = [];
let ageNumber = null;
if (name === "") {
errors.push("名前を入力してください。");
}
if (ageText === "") {
errors.push("年齢を入力してください。");
} else {
const age = Number(ageText);
if (Number.isNaN(age)) {
errors.push("年齢は数字で入力してください。");
} else if (age <= 0) {
errors.push("年齢は1以上の数で入力してください。");
} else {
ageNumber = age;
}
}
return { errors, ageNumber };
}
JavaScriptイベントハンドラ側はこうなります。
submitButtonElement.addEventListener("click", () => {
const name = nameInputElement.value.trim();
const ageText = ageInputElement.value.trim();
nameInputElement.classList.remove("error");
ageInputElement.classList.remove("error");
const result = validateProfile(name, ageText);
const errors = result.errors;
const ageNumber = result.ageNumber;
if (name === "") {
nameInputElement.classList.add("error");
}
if (ageText === "" || Number.isNaN(Number(ageText)) || Number(ageText) <= 0) {
ageInputElement.classList.add("error");
}
if (errors.length > 0) {
messageElement.textContent = errors.join(" ");
return;
}
messageElement.textContent = `${name} さんは ${ageNumber} 歳ですね。`;
});
JavaScriptここで大事なのは、「チェックのルール」を関数に閉じ込めたことです。
イベントハンドラは「値を集める」「結果を表示する」役
validateProfile は「値が正しいかどうかを判定する」役
役割を分けることで、
バリデーションのルールを変更したいときに、
どこを触ればいいかが明確になります。
フォーム送信(submit)と組み合わせる
Enter キーでも同じチェックを走らせる
Day18 でやったように、form と submit イベントを使うと、
ボタンクリックと Enter キーを同じ流れで扱えます。
<form id="profileForm">
<p>
名前:<input id="nameInput" type="text">
</p>
<p>
年齢:<input id="ageInput" type="text">
</p>
<button type="submit">送信</button>
</form>
<p id="message"></p>
const profileFormElement = document.getElementById("profileForm");
const nameInputElement = document.getElementById("nameInput");
const ageInputElement = document.getElementById("ageInput");
const messageElement = document.getElementById("message");
profileFormElement.addEventListener("submit", (event) => {
event.preventDefault();
const name = nameInputElement.value.trim();
const ageText = ageInputElement.value.trim();
nameInputElement.classList.remove("error");
ageInputElement.classList.remove("error");
const errors = [];
if (name === "") {
errors.push("名前を入力してください。");
nameInputElement.classList.add("error");
}
if (ageText === "") {
errors.push("年齢を入力してください。");
ageInputElement.classList.add("error");
} else {
const age = Number(ageText);
if (Number.isNaN(age)) {
errors.push("年齢は数字で入力してください。");
ageInputElement.classList.add("error");
} else if (age <= 0) {
errors.push("年齢は1以上の数で入力してください。");
ageInputElement.classList.add("error");
} else {
messageElement.textContent = `${name} さんは ${age} 歳ですね。`;
}
}
if (errors.length > 0) {
messageElement.textContent = errors.join(" ");
}
});
JavaScriptsubmit + preventDefault +入力チェック、という組み合わせは、
実際のフォーム処理の“型”そのものです。
セキュリティと UX のバランス
「厳しくチェックする」と「分かりやすく伝える」はセット
入力チェックは、セキュリティの観点から「厳しくする」ことが大事ですが、
同時に「どこがダメなのかを分かりやすく伝える」ことも重要です。
そのためにやっているのが、
どの項目がエラーかをクラスで示す
エラーメッセージを画面の決まった場所に出す
複数のエラーをまとめて表示する
という工夫です。
「ただ弾く」のではなく、
「どう直せばいいかを教える」入力チェックが書けると、
コードも UI も一気にプロっぽくなります。
Day19 後半のミニ総合サンプル
エラー表示+見た目の強調をまとめたフォーム
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Day19 条件 + DOM 後半</title>
<style>
.error {
border: 2px solid red;
background-color: #ffecec;
}
.error-message {
color: red;
font-size: 12px;
}
</style>
</head>
<body>
<h1>会員登録フォーム(風)</h1>
<form id="registerForm">
<p>
ユーザー名:<input id="userInput" type="text">
</p>
<p>
年齢:<input id="ageInput" type="text">
</p>
<button type="submit">登録</button>
</form>
<p id="message" class="error-message"></p>
<script>
const registerFormElement = document.getElementById("registerForm");
const userInputElement = document.getElementById("userInput");
const ageInputElement = document.getElementById("ageInput");
const messageElement = document.getElementById("message");
registerFormElement.addEventListener("submit", (event) => {
event.preventDefault();
const user = userInputElement.value.trim();
const ageText = ageInputElement.value.trim();
userInputElement.classList.remove("error");
ageInputElement.classList.remove("error");
const errors = [];
if (user === "") {
errors.push("ユーザー名を入力してください。");
userInputElement.classList.add("error");
} else if (user.length > 20) {
errors.push("ユーザー名は20文字以内で入力してください。");
userInputElement.classList.add("error");
}
if (ageText === "") {
errors.push("年齢を入力してください。");
ageInputElement.classList.add("error");
} else {
const age = Number(ageText);
if (Number.isNaN(age)) {
errors.push("年齢は数字で入力してください。");
ageInputElement.classList.add("error");
} else if (age < 13) {
errors.push("13歳未満は登録できません。");
ageInputElement.classList.add("error");
}
}
if (errors.length > 0) {
messageElement.textContent = errors.join(" ");
return;
}
messageElement.textContent = `登録が完了しました。ようこそ、${user} さん。`;
userInputElement.value = "";
ageInputElement.value = "";
});
</script>
</body>
</html>
ここには、Day19 後半でやりたかったことが全部入っています。
複数条件の入力チェック
エラーの蓄積とまとめて表示
エラー項目へのクラス付与
submit + preventDefault のフォーム処理
Day19 後半のまとめ
Day19 後半では、
「入力チェックをちゃんと設計する」という一段上のステージに入りました。
複数エラーを配列でためてまとめて表示する
どの項目がエラーかを classList で見た目に反映する
バリデーションロジックを関数に切り出して整理する
submit イベントと組み合わせて、フォームとして自然に動かす
ここまでできていると、
「入力をそのまま信用しない」「条件で守る」という感覚が、
かなり本物になってきています。
この先、サーバー通信やデータ保存に進んでも、
今日の「入力チェックの型」はずっと使い続けることになります。
