JavaScript | ゼロからはじめるプログラミング、30日で基礎を学ぶJavaScript:Webページを操作できるようになる - Day19:条件 + DOM

JavaScript JavaScript
スポンサーリンク

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(" ");
  }
});
JavaScript

submit + 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 イベントと組み合わせて、フォームとして自然に動かす

ここまでできていると、
「入力をそのまま信用しない」「条件で守る」という感覚が、
かなり本物になってきています。

この先、サーバー通信やデータ保存に進んでも、
今日の「入力チェックの型」はずっと使い続けることになります。

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