JS / 前端技術 / 筆記 · 2019-10-21

Plugin validate.js 表單套件

官網:https://validatejs.org/#installing

☞ 安裝

瀏覽器 / CDN

<script src="//cdnjs.cloudflare.com/ajax/libs/validate.js/0.12.0/validate.min.js"></script>

npm / node.js

$ npm install --save validate.js

var validate = require("validate.js");

Bower

$ bower install --save validate.js

Component

$ component install ansman/validate.js

☞ 格式

用法

//用法
<attribute>: {
  <validator name>: <validator options>
}

運用說明

//Javascript 範例
email: {
  presence: true, // Email 是必填欄位
  email: true // 需要符合 Email 格式
},
//Html
<input id="email" class="form-control" type="email" placeholder="Email" name="email">

預設驗證規則

required: true // 必填
remote: 'akacodedog.php' // 使用ajax指定akacodedog.php驗證
email: true // 驗證email格式
url: true // 驗證網址格式
date: true // 驗證日期格式
dateISO: true // 驗證ISO日期格式
number: true // 驗證數字
digits: true // 限制整數
creditcard: '' // 驗證信用卡號
equalTo: '' // 限制輸入內容與某元素相同
accept: '' // 限制上傳檔案副檔名
maxlength: 3 // 限制最大輸入長度為3
minlength: 10 // 限制最小輸入長度為10
rangelength: [3, 10] // 限制輸入長度必須是3~10
range: [3, 10] // 限制輸入數字必須是3~10
max: 3 // 限制輸入數字不可大於3
min: 10 // 限制輸入數字不可小於10

預設提示

required: This field is required.
remote: Please fix this field.
email: Please enter a valid email address.
url: Please enter a valid URL.
date: Please enter a valid date.
dateISO: Please enter a valid date (ISO).
dateDE: Bitte geben Sie ein gltiges Datum ein.
number: Please enter a valid number.
numberDE: Bitte geben Sie eine Nummer ein.
digits: Please enter only digits
creditcard: Please enter a valid credit card number.
equalTo: Please enter the same value again.
accept: Please enter a value with a valid extension.
maxlength: Please enter no more than {0} characters.
minlength: Please enter at least {0} characters.
rangelength: Please enter a value between {0} and {1} characters long.
range: Please enter a value between {0} and {1}.
max: Please enter a value less than or equal to {0}.
min: Please enter a value greater than or equal to {0}.

☞ 範例

簡易表單範例

 //Javascript   
(function() {
      validate.extend(validate.validators.datetime, {
        parse: function(value, options) {
          return +moment.utc(value);
        },
        format: function(value, options) {
          var format = options.dateOnly ? "YYYY-MM-DD" : "YYYY-MM-DD hh:mm:ss";
          return moment.utc(value).format(format);
        }
      });
      var constraints = {
        "email": {  
          presence:  {
            message: "是必填的欄位"
          }, // Email 是必填欄位
          email: true // 需要符合 email 格式
        },
        "密碼": {
          presence: {
            message: "是必填的欄位"
          }, // 密碼是必填欄位
          length: {
            minimum: 5, // 長度大於 5
            maximum: 12, // 長度小於 12
            message: "^密碼長度需大於 5 小於 12"
          },
        },
        "確認密碼": {  
          presence: {
            message: "是必填的欄位"
          },// 確認密碼是必填欄位
          equality: {
            attribute: "password",// 此欄位要和密碼欄位一樣
            message: "^密碼不相同"
          }
        },
        "使用者名稱": {
          presence: {
            message: "是必填的欄位"
          }, // 必填使用者名稱
          length: {
            minimum: 3, // 名稱長度要超過 3 
          },
          format: {
            pattern: "[a-z0-9]+", // 只能填入英文或數字
            flags: "i",// 大小寫不拘
            message: "只能包含 a-z 和 0-9"
          }
        },
        '生日': {
           presence: {
            message: "是必填的欄位"
          }, // 生日欄位是必填
           date: {
            latest: moment().subtract(18, "years"), // 年齡滿 18
            message: "^超過 18 歲才可以使用這個服務哦~"
          }
        },
        "所在地": {
          presence: {
            message: "是必填的欄位"
          }, // 所在地為必填
          inclusion: {
            within: ["KS"],  // 只有在 within 的才驗證通過
            message: "^Sorry, 這個服務只提供給高雄"
          }
        },
        "電話": {
          presence:{
            message: "是必填的欄位"
          },
        },
      };

      // Hook up the form so we can prevent it from being posted
      var form = document.querySelector("form#main");
      form.addEventListener("submit", function(ev) {
        ev.preventDefault();
        handleFormSubmit(form);
      });
      
      // 監聽 input 值改變的狀況
      var inputs = document.querySelectorAll("input, textarea, select")
      for (var i = 0; i < inputs.length; ++i) {
        inputs.item(i).addEventListener("change", function(ev) {
          var errors = validate(form, constraints) || {};
          showErrorsForInput(this, errors[this.name])
        });
      }

      // 沒有錯誤就顯示成功傳送
      function handleFormSubmit(form, input) {
        var errors = validate(form, constraints);// validate the form aainst the constraints
        showErrors(form, errors || {}); // then we update the form to reflect the results
        if (!errors) {
          showSuccess();
        }
      }

      // Updates the inputs with the validation errors
      function showErrors(form, errors) {
        // We loop through all the inputs and show the errors for that input
        _.each(form.querySelectorAll("input[name], select[name]"), function(input) {
          // Since the errors can be null if no errors were found we need to handle
          // that
          showErrorsForInput(input, errors && errors[input.name]);
        });
      }

      // Shows the errors for a specific input
      function showErrorsForInput(input, errors) {
        // This is the root of the input
        var formGroup = closestParent(input.parentNode, "form-group")
          // Find where the error messages will be insert into
          , messages = formGroup.querySelector(".messages");
        // First we remove any old messages and resets the classes
        resetFormGroup(formGroup);
        // If we have errors
        if (errors) {
          // we first mark the group has having errors
          formGroup.classList.add("has-error");
          // then we append all the errors
          _.each(errors, function(error) {
            addError(messages, error);
          });
        } else {
          // otherwise we simply mark it as success
          formGroup.classList.add("has-success");
        }
      }

      // Recusively finds the closest parent that has the specified class
      function closestParent(child, className) {
        if (!child || child == document) {
          return null;
        }
        if (child.classList.contains(className)) {
          return child;
        } else {
          return closestParent(child.parentNode, className);
        }
      }

      function resetFormGroup(formGroup) {
        // Remove the success and error classes
        formGroup.classList.remove("has-error");
        formGroup.classList.remove("has-success");
        // and remove any old messages
        _.each(formGroup.querySelectorAll(".help-block.error"), function(el) {
          el.parentNode.removeChild(el);
        });
      }

      // Adds the specified error with the following markup
      // <p class="help-block error">[message]</p>
      function addError(messages, error) {
        var block = document.createElement("p");
        block.classList.add("help-block");
        block.classList.add("error");
        block.innerText = error;
        console.log(block);
        messages.appendChild(block);
      }
      function showSuccess() {
        alert("Success!"); // We made it \:D/
      }
    })();
<!--css-->
<style>
.container {
  width: 900px;
  margin: 0 auto;
}
.container h1 {
  margin: 20px;
  text-align: center;
}
.container form {
  padding: 20px;
  background: #EBF0F4;
  border-radius: 10px;
}
.help-block.error {
  margin-bottom: 5px;
}
.messages{
  margin: 10px 5px;
  color: #dc3545
}
</style>

<!--html-->
<div class="container">
  <h1>validate.js 範例</h1>
  <form id="main">
    <div class="form-row">
      <div class="form-group col-md-6">
        <label for="email">Email</label>
        <input id="email" class="form-control" type="email" placeholder="Email" name="email">
        <div class="messages"></div>
      </div>
      <div class="form-group col-md-6">
        <label for="password">密碼</label>
          <input id="password" class="form-control" type="password" placeholder="Password" name="密碼">
        <div class="messages"></div>
      </div>
    </div>
    <div class="form-group">
      <label for="confirm-password">確認密碼</label>
      <input id="confirm-password" class="form-control" type="password" placeholder="Confirm password" name="確認密碼">
      <div class="messages"></div>
    </div>
    <div class="form-row">
      <div class="form-group col-md-6">
        <label for="username">使用者名稱</label>
        <input id="username" class="form-control" type="text" placeholder="Username" name="使用者名稱">
        <div class="messages"></div>
      </div>
      <div class="form-group col-md-6">
        <label for="birthdate">生日</label>
        <input id="birthdate" class="form-control" type="date" placeholder="YYYY-MM-DD" name="生日">
        <div class="messages"></div>
      </div>
    </div>
    <div class="form-row">
      <div class="form-group col-md-6">
        <label for="country">所在地</label>
          <select id="country" class="form-control" name="所在地">
            <option value=""></option>
            <option value="KS">高雄</option>
            <option value="TC">台南</option>
            <option value="TP">台北</option>
          </select>
        <div class="messages"></div>
      </div>
      <div class="form-group col-md-6">
        <label for="phone">電話</label>
        <input id="phone" class="form-control" type="text" placeholder="0912-345-678" name="電話">
        <div class="messages"></div>
      </div>
    </div>
    <button type="submit" class="btn btn-primary">註冊</button>
  </form>
</div>