フォームのバリデーションをユーザーの入力が完了してから行う(JavaScript)

# やりたいこと
フォームの入力に対するバリデーションをユーザーの入力が終わるまで待機して，入力が完了(入力欄からフォーカスが外れる)してからバリデーションをする

# 使用ライブラリ
* Bootstrap 4
* JavaScript

# Bootstrapでバリデーション
Bootstrapでは`was-validated`というクラスをinputタグを囲っているdivタグに追加することでバリデーションの結果を入力欄の枠の色で分かりやすく表示してくます．

実際に例としてメールを入力する欄を作成します． (必須の入力としています)

```html
<body>
  <form action="" method="POST" enctype="multipart/form-data">
    <div class="form-group was-validated" id="mail_div">
      <label for="mail" class="font-weight-bold">E-mail</label>
      <input type="email" id="mail" required class="form-control" name="user_email" placeholder="Ex) sample@sample.com" autocomplete="email">
    </div>
    <div class="input">
      <button type="submit" class="btn btn-primary">Submit</button>
    </div>
  </form>
</body>
```

以下に実際の例を表示します． 

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="yutake27" data-slug-hash="oNYyGPQ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="email valid always">
  <span>See the Pen <a href="https://codepen.io/yutake27/pen/oNYyGPQ">
  email valid always</a> by yutake27 (<a href="https://codepen.io/yutake27">@yutake27</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

ここではメールの入力が必須となっているので何も入力されていない状態は不正な状態です．
そのため最初から赤い枠で入力欄が囲まれています．

しかしこれから入力を行うのに最初から赤で囲まれているのはあまり良い気分ではありません．

さらにこの状態では入力をしている最中にも文字を1文字打つごとにバリデーションの結果が更新されます．

上記入力欄で実際に試してもらうと分かりますが，`sample@sample.com`を打つ際に`sample@s`まで打ったところで一度入力欄の枠の色が緑になります．
![スクリーンショット 2021-03-06 15.40.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401124/36e90526-9fb8-d467-990f-0f55bacf5364.png)
その後`sample@sample.`まで打ったところでもう一度枠が赤になります．
![スクリーンショット 2021-03-06 15.41.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401124/e478b578-ce44-6803-62e8-34143ae9c381.png)
`sample@sample.c`まで打つとようやく緑になります．

このように入力中にコロコロ枠の色が変わるのは好ましくありません．

色々な記事で入力中のバリデーションはやめた方がいいと指摘されていました．
[入力フォームをリアルタイムチェックを実装する際に気を付けるべきポイント](https://act-3.biz/real-time-check/)
[ユーザーをイラつかせているかも？確実に避けたいフォームヴァリデーション（入力チェック機能）7つの禁じ手](https://ferret-plus.com/7724)

そこでJavaScriptを用いて入力が完了してからバリデーションを行うようにしました．


# ユーザーの入力が完了してからバリデーション
JavaScriptのコードは次のようになります．

```JavaScript
const mail = document.getElementById('mail');
const mail_div = document.getElementById('mail_div');
mail.addEventListener('focus', TurnOffValid);
function TurnOffValid() {
  mail_div.classList.remove('was-validated');
}
mail.addEventListener('blur', validMail);
function validMail() {
  if (mail.value != "") {
    mail_div.classList.add('was-validated');
  }
}
```
ユーザーがmail入力欄にフォーカスを当てた際に`was-validated`クラスを削除して，入力欄からフォーカスが外れた際に`was-validated`クラスを追加しています．

さらに入力欄に文字が何も入力されていない時はユーザーは入力を開始していないと判断して`was-validated`クラスを付与しないようにしました．


実際の実行例が以下になります．
<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="yutake27" data-slug-hash="yLVEzmz" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="email valid after finish typing">
  <span>See the Pen <a href="https://codepen.io/yutake27/pen/yLVEzmz">
  email valid after finish typing</a> by yutake27 (<a href="https://codepen.io/yutake27">@yutake27</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

入力している最中は枠の色が青になり，入力が完了したら(入力欄からフォーカスを外したら)バリデーションの結果に応じて枠の色が変化すると思います．

## 感想
色々なところでこのような処理が行われていると思うのですが意外と参考になる実装があまりなくて(自分のサーチ力のせい？）JavaScript初心者の自分は苦労しました．

## 参考
[イラっとしない超ミニマルなフォームバリデーションを素のJSで実装しよう](https://www.webprofessional.jp/instant-validation/)
[addEventListener type一覧と各ブラウザ対応](https://qiita.com/mrpero/items/156968e3512d42fffc5e)
[とほほのBootstrap 4入門](http://www.tohoho-web.com/bootstrap/forms.html?)