【JavaScript】JavaScriptでバリデーションを実装する。

以下の項目を満たすバリデーションをjavascriptで実装してみる。
テンプレートエンジンはejs。フレームワークはexpress

- パスワードが７文字以上
- パスワードが確認用と一致している
- 全ての項目が入力されている
- 問題なかったら、ホーム画面へ

現在の状況
サインアップのフロントページ作成済
![bc216d7ecd548acd6ecb29001bf34918.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/addb9c54-2a4b-8142-5e38-49d563a4aa2e.png)


ログイン画面とサインアプページへのルーティング設定済

```routes/users.js
const express = require('express');
const router = express.Router();

/* GET users listing. */
router.get('/login', function(req, res, next) {
  res.render('users/login');
});

router.get('/signup', function(req, res, next) {
  res.render('users/signup');
});

module.exports = router;
```


１ とりあえずホーム画面のルーティング作成

```src/routes/home.js
const express = require('express');
const router = express.Router();

router.get('/', function(req, res, next) {
  res.render('home');
});

module.exports = router;
});
```

２ ホーム画面の仮作成

```src/views/home.ejs
home
```

３ アクセスしてみる

http://localhost:3000/home

```
Error: Failed to lookup view "error" in views directory "/app/views"
    at Function.render (/app/node_modules/express/lib/application.js:580:17)
    at ServerResponse.render (/app/node_modules/express/lib/response.js:1008:7)
    at /app/app.js:38:7
    at Layer.handle_error (/app/node_modules/express/lib/router/layer.js:71:5)
    at trim_prefix (/app/node_modules/express/lib/router/index.js:315:13)
    at /app/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/app/node_modules/express/lib/router/index.js:335:12)
    at next (/app/node_modules/express/lib/router/index.js:275:10)
    at /app/app.js:27:3
    at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
```

エラー、、、

ルーティングが間違っている？

app.jsに登録してなかった。この辺の挙動はあまり理解していないが、とりあえず動作するようにしてみる。

```app.js
const homeRouter = require('./routes/home');

app.use('/home', homeRouter);

を追記
```
再度アクセスしてみる。
オッケー

４ ejsを使用できるようにする。
　　(1)npm install ejsについてはdocker build時に実施済
　　(2)setメソッドで"view engine"というconfigに対し、テンプレートエンジンを指定

```app.js
// テンプレートエンジンの指定
app.set("view engine", "ejs");
を追記
```

５ login画面でレンダリングできるかテストしてみる。

```login.ejs

  <% const item = 'apple' %>
  <%= item %>
```
こんな感じで表示できるか確認。

![2e528c8605286cbf073f14682b34ba4a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547556/1287c074-984b-ecca-09d6-b61c226d631a.png)

できた。

ログインページでjavascriptの読み込み

```login.ejs
<script type="text/javascript" src='/javascript/validator.js'></script>
```

javascriptファイルの作成
/src/public/javascript/validator.js

6 各フォームに空欄エラー文を仕込む

```signup.ejs
<input type="text" class="form-control col-7" id="NameForm" aria-describedby="namelHelp" 
 placeholder="Enter name">
<span id="error-name-null" class="d-none">必ず入力してください</span>
```
各フォームも同様。初期値は d-none で非表示にしている。
パスワード確認フォームには仕込まない。パスワードが空欄の場合エラー及びパスワードと空欄が一致する必要があるので、
パスワード確認が空欄の時、通ることはない。（共に空欄の場合一致はしてるが、パスワードが空欄エラー。パスワードが入力されている時、確認パスワードが空欄なら不一致エラーとなる）

7　フォームにonsubmitを仕込む

```html
signup.ejs

<form class='col-7 mt-3 border pl-0 pr-0' onsubmit="return checkForm()">
```
onsubmitメソッド:
form要素に記述し、送信ボタンを押したとき（submit）に起動するスクリプトを指定するイベント属性（イベントハンドラ）。
起動するスクリプトは、属性値に "return 関数名()" と書く。
"true" を返せばフォームのアクションを実行し、"false" なら実行をキャンセルする。

8 空欄時の処理（名前入力欄）

```validator.js
const checkForm = (e) => {
  const nameValue = document.getElementById("NameForm").value;
  let cancel = "off";
  //再クリック時に一旦、エラーメッセージを消去。（でないと残り続ける）
  document.getElementById('error-name-null').classList.add("d-none");

    if (!(nameValue)) {
      document.getElementById('error-name-null').classList.remove("d-none");
      cancel = "on";
    }
    if (cancel === "on"){
      return false;
    } else {
      return true;
    }
}
```
名前フォームが空欄の場合は、エラーメッセージを表示させる。
cancelフラグにonを格納。
cancelがonの時はonsubmitにfalseを返す。

9 パスワード欄の処理

```javascript
    // パスワード空欄
    if (!(passwordValue)) {
      document.getElementById('error-password-null').classList.remove("d-none");
      cancel = "on";
    } else {
      // パスワード７文字以下
      if ((passwordValue.length < 7)) {
        document.getElementById('error-password-under7').classList.remove("d-none");
        cancel = "on";
      }
    }
```
空欄時に重複表示（空欄エラーと、７文字エラー）を避けるため、空欄時には７文字チェックは通過させない。

##全文（装飾クラスは省略）

```validator.js
  const checkForm = (e) => {
  const nameValue = document.getElementById("NameForm").value;
  const mailValue = document.getElementById("EmailForm").value;
  const passwordValue = document.getElementById("PasswordForm").value;
  const confirmPasswordValue = document.getElementById("confirmPasswordForm").value;
  const btn = document.getElementById("btn");
  let cancel = "off";

  document.getElementById('error-name-null').classList.add("d-none");
  document.getElementById('error-mail-null').classList.add("d-none");
  document.getElementById('error-password-null').classList.add("d-none");
  document.getElementById('differencePassword').classList.add("d-none");
  document.getElementById('error-password-under7').classList.add("d-none");

    // 名前空欄
    if (!(nameValue)) {
      document.getElementById('error-name-null').classList.remove("d-none");
      cancel = "on";
    }
    // メール空欄
    if (!(mailValue)) {
      document.getElementById('error-mail-null').classList.remove("d-none");
      cancel = "on";
    }
    // パスワード空欄
    if (!(passwordValue)) {
      document.getElementById('error-password-null').classList.remove("d-none");
      cancel = "on";
    } else {
      // パスワード７文字以下
      if ((passwordValue.length < 7)) {
        document.getElementById('error-password-under7').classList.remove("d-none");
        cancel = "on";
      }
    }
    // パスワード不一致
    if (!(passwordValue === confirmPasswordValue)) {
      document.getElementById('differencePassword').classList.remove("d-none");
      cancel = "on";    }
    if (cancel === "on"){
      return false;
    } else {
      return true;
    }
}
```

```html
signup.js  #フォーム部分のみ 装飾用クラスは省略

        <!-- フォーム -->
        <form action="/home" method="post" onsubmit="return checkForm()">
          <!-- 名前 -->
            <input type="text" id="NameForm" >
            <span id="error-name-null" class="d-none">必ず入力してください</span>
          <!-- メール -->
            <input type="email" id="EmailForm">
            <span id="error-mail-null" class="d-none">必ず入力してください</span>
          <!-- パスワード -->
            <input type="password" id="PasswordForm">
            <span id="error-password-null" class="d-none">必ず入力してください</span>
            <span id="error-password-under7" class="d-none">7文字以上</span>
          <!-- パスワード確認 -->
            <input type="password" id="confirmPasswordForm">
            <span id="differencePassword" class="d-none">一致していません</span>
          <!-- ボタン -->
            <button id="btn">Register</button>
        </form>
```