フロント側でフォームのバリデーションを追加したのでその忘備録


Qiita初投稿です。
とある会社でフロント開発に携わらせていただいてます。

フォームの作成において
「inputタグに特定のクラスをつけるだけで必須項目として認識するようにしたい」
とふと思ったのでjQueryを使って作成してみました。

#### バリデーション
入力内容が適当かどうかを入力チェックすこと
(必須項目です！ 適切なメールアドレスを記入してください! などとお叱りをいただけます)

#### 正規表現
正規表現とは、「さまざまな文字列を一つの文字列で表すことができる記法」です。
javascriptだと`/ac+c/`などのようなスラッシュで囲まれた正規表現リテラルを利用します。
https://okinawanpizza.hatenablog.com/entry/2020/05/22/104507

例)
`^[A-Za-z0-9]{1}` = 先頭がアルファベットもしくは数字の文字列

#### 電話番号、メールアドレスのチェック
先程の正規表現を用いると以下のようなチェックが可能となります。

```
//メールアドレスのバリデーション(例)
var regexp = /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/;
 if (!regexp.test(content)) {
  //正規表現とマッチしなかった時の処理
 }
```
test()メソッドは、正規表現と指定された文字列が一致するかどうかを調べるメソッドです。論理値を返却します。  

```
//電話番号のバリデーション(例)  
let contentTel = content.replace(/\D/g, '');
if !contentTel.match(/^(0[5-9]0[0-9]{8}|0[1-9][1-9][0-9]{7})$/)) {
 flag = true;
}
``` 
replace()メソッドは文字列の中にある、指定した文字列を別の文字列へと置換してくれます。
ここで数字以外の文字をトリミングしてくれます。

--追記--
電話番号のトリミングの部分に関しましてアドバイスいただきました。
@mmnn2o さんありがとうございます!!

###指定した入力項目だけを必須項目にする  

本題です(笑)
inputタグに "require"というクラスをつけるだけで入力チェックを行えるようにします。
![](https://tech.pla-cole.co/wp-content/uploads/2021/05/スクリーンショット-2021-05-01-11.46.45-300x174.png)

手順は以下の通り。

```
①requireがついたinputタグのバリデーション結果を記憶するためのハッシュを作る。
②requireという名前のクラスがついたinput全てに背番号をつけてハッシュに格納する。
③入力が終了した瞬間に入力チェックを行い、結果をハッシュに登録する。
④入力項目のタイプに応じたバリデーション処理を作成する。
⑤ハッシュの値全てがtrueなら、送信ボタンを押せる状態にする。
⑥おまけ：input以外のチェック項目を追加したい...
```

##### ①、②必須項目を登録
```
  let valitationHash = {};
  let $require = $(".require");
  $require.each(function (index, element) {
    let name = "input" + index;
    $(element).attr("data-input-name", name);  //⑥番のおまけで少し変更あり
    valitationHash[name] = false;  //valitationHash = {input1: false, input2: false, ....}
  })
```
requireのついたinput要素にdata-input-name属性を追加します。
こちらの値が背番号となり、入力チェックのタイミングで使用します。 
ハッシュの中は`valitationHash = {input1: false, input2: false, ....}`となり
⑤のチェック段階では全ての値がtrueになれば送信を押せるようにします。

##### ③入力チェックの結果をハッシュに登録
```
  $(".require").change(function() {
    checkValitate(this);
  })
  function checkValitate(elem) {
    let type = $(elem).attr("type");
    let name = $(elem).attr("data-input-name");
    let flag = true;
    let content = $(elem).val();
    if(type == 'text') { //type="text"の場合の入力チェック
      if(content == ""){
        flag = false;
      }
    } else if (type == 'email') { //type="email"の場合の入力チェック
      var regexp = /^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/;
      if (!regexp.test(content)) {
        flag = false;
      }
    } else if (type == 'tel') {
      let contentTel = content.replace(/[━.*‐.*―.*－.*\-.*ー.*\-]/gi,'');
      console.log(contentTel);
      if (!contentTel.match(/^(0[5-9]0[0-9]{8}|0[1-9][1-9][0-9]{7})$/)) {
        flag = false;
      } else if (type == 'example'){
	    if(checkExample()){
		  flag = false;
		}
	  } 
    setValitationHash(name , flag)  //⑤番号とチェック結果を引数として渡します
  }
```
inputのタイプべつにバリデーションの項目が違うので
入力項目の種類別に分岐させます。

##### ⑤ハッシュの値全てがtrueなら、ボタンを押せるようにする
```
  function setValitationHash (name, boolean){
    valitationHash[name] = boolean; 
    pushable(valitationHash);
  }
  function pushable (hash) {
    let pushableValue = true;
    for (let key in hash) {
      if(hash[key] == false){
       pushableValue = false;
      }
    }
    if(pushableValue){
     buttonOn()
    } else {
     buttonOff()
    }
  }
  function buttonOn() {
    $(".button").prop("disabled", false);
  }
  function buttonOff() {
    $(".button").prop("disabled", true);
  }
```
for..in..文を利用してハッシュの全ての値をチェックします。
全てtrueであれば送信可能にして完了です。

```
//for in サンプル
let ageList = {yusaku:"12", kiyomi: "25", yuki: "30"};
 for (let name in ageList) {
  console.log("私は" + name + "、" + ageList[name] + "です。")
 }
```

### おまけ
フォームってinputタグだけじゃないことをすっかり忘れておりました。
![](https://tech.pla-cole.co/wp-content/uploads/2021/05/スクリーンショット-2021-05-01-13.20.45-300x174.png) 
どうにかselectタグもrequire仲間に加えてあげたい、、

##### ⑥selectタグを認識できるように修正
汎用性を持たせるために、
inputの属性に新しく data-input-typeを追加します。

```
  $require.each(function (index, element) {
    let name = "input" + index;
    setTypeAndName(element, name)
    valitationHash[name] = false;
  })
  function setTypeAndName(element, name) {
    let type = "text"; 
    let tagname = $(element).prop("tagName");
    if(tagname == "SELECT"){
      type = "select";
    } else if (tagname == "INPUT"){
      type = $(element).attr("type");
    } else if (tagname == "SPAN") {
      type = "checkbox"
    }
    $(element).attr("data-input-name", name);
    $(element).attr("data-input-type", type);
  }
```
タグの名前で判別してdata-input-type属性に"select"を追加しました。
prop("tagName")でタグの値を取得できます。
そしてcheckValitate(elem)関数にdata-input-type属性がselect時のパターンを追加します。

```
function checkValitate(elem) {
 let type = $(elem).attr("data-input-type"); // type属性ではなくdata-input-type属性を取得するように処理を変更
 .
 .c
 } else if (type == 'select') {
  //処理内容
 }
 .
 .
}
```

### おしまい

今回Qiitaに初めて投稿させていただきました。
今回のコーディングでバリデーションの他のライブラリを調べるきっかけにもなってすごくいい経験になりました。
また、ワードプレスのコンタクトフォーム7など
フロントでのバリデーション設定がないものでも意外に使えたりしたので、よかったかなと思います(笑)

未経験からweb制作に携わらせていただき一年が経ちましたがやっぱりJavaScriptを触るのは楽しいですね。
もっといい方法があればアドバイスいただけると嬉しいです。励みになります。
ご清澄ありがとうございました！！

参考
test()メソッド
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test

正規表現
https://qiita.com/soarflat/items/2b50c1efe2ea54a762d7

連想配列をループさせる
https://qiita.com/wifeofvillon/items/15359535a834832e08ea