■ サンプル
<!doctype html> <html lang="jp"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous"> <title>Hello, world!</title> </head> <body> <div class="container"> <form id="sampleForm" class="needs-validation" action="" method="post" novalidate> <div class="form-row"> <div class="col-md-4 mb-3"> <label for="validationCustom01">名字</label> <input type="text" class="form-control" id="validationCustom01" placeholder="名字" name="familyName" value="" required> <div class="invalid-feedback"> 名字を入力してください </div> <div class="valid-feedback"> 入力済! </div> </div> <div class="col-md-4 mb-3"> <label for="validationCustom02">名前</label> <input type="text" class="form-control" id="validationCustom02" placeholder="名前" name="firstName" value="" required> <div class="invalid-feedback"> 名前を入力してください </div> </div> <div class="col-md-4 mb-3"> <label for="validationCustomUsername">ユーザー名</label> <div class="input-group"> <div class="input-group-prepend"> <span class="input-group-text" id="inputGroupPrepend">@</span> </div> <input type="text" class="form-control" id="validationCustomUsername" name="userName" placeholder="ユーザー名" aria-describedby="inputGroupPrepend" required> <div class="invalid-feedback"> ユーザー名を選択してください </div> </div> </div> </div> <div class="form-row"> <div class="col-md-6 mb-3"> <label for="validationCustomDateStart">開始日</label> <input type="date" class="form-control" id="validationCustomDateStart" name="startDate" placeholder="開始日" oninput="isValidDates();" required> <div class="invalid-feedback"> 開始日を入力してください </div> <div class="valid-feedback"> 入力済! </div> </div> <div class="col-md-6 mb-3"> <label for="validationCustomDateEnd">終了日</label> <input type="date" class="form-control" id="validationCustomDateEnd" name="endDate" placeholder="終了日" oninput="isValidDates();"> <div class="invalid-feedback"> 開始日より未来日付は指定できません </div> </div> </div> <div class="form-group"> <div class="form-check"> <input class="form-check-input" type="checkbox" value="" id="invalidCheck" name="agreement" required> <label class="form-check-label" for="invalidCheck"> 利用規約に同意する </label> <div class="invalid-feedback"> 提出する前に同意する必要があります </div> </div> </div> <button type="submit" class="btn btn-primary">フォームを送信</button> </form> </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script> <script> // 無効なフィールドがある場合にフォーム送信を無効にするスターターJavaScriptの例 (function() { 'use strict'; window.addEventListener('load', function() { // カスタムブートストラップ検証スタイルを適用するすべてのフォームを取得 var forms = document.getElementsByClassName('needs-validation'); // ループして帰順を防ぐ var validation = Array.prototype.filter.call(forms, function(form) { form.addEventListener('submit', function(event) { if (form.checkValidity() === false) { event.preventDefault(); event.stopPropagation(); } form.classList.add('was-validated'); }, false); // 有効な値になるまでボタンが活性化されない //form.addEventListener('input', function(event) { // $(this).find(':submit').attr('disabled', !this.checkValidity()); //}); }); }, false); })(); $('#sampleForm').submit(function() { return isValidDates(); }); function isValidDates() { console.log("Enter..."); var inputCustomDateEnd = document.getElementById("validationCustomDateEnd"); inputCustomDateEnd.setCustomValidity(""); var endDateValue = $("#validationCustomDateEnd").val(); if (!endDateValue) { return true; } var startDate = new Date($("#validationCustomDateStart").val()); var endDate = new Date(endDateValue); if (endDate < startDate) { inputCustomDateEnd.setCustomValidity("開始日より未来日付は指定できません"); console.log("Error"); return false; } return true; } </script> </body> </html>
■ 補足:制約検証API
http://cccabinet.jpn.org/bootstrap4/components/formsより抜粋 ~~~~~~~~~~~~~ ・すべての最新ブラウザは、フォームコントロールを検証する一連の JavaScriptメソッドである制約検証APIをサポート済み。 ・JavaScriptで setCustomValidity を使用してカスタムの有効性メッセージを提供可能。 ~~~~~~~~~~~~~
setCustomValidity()
https://syncer.jp/Web/API_Interface/Reference/IDL/HTMLInputElement/setCustomValidity/・input要素を、任意のメッセージを指定してカスタム検証エラー状態にする ・空の文字列を指定した場合は、カスタム検証エラー状態を解除
checkValidity()
https://syncer.jp/Web/API_Interface/Reference/IDL/HTMLInputElement/checkValidity/・input要素の入力内容の検証を実行 => 検証エラーがある場合にだけ、invalidイベントが発生 ・返り値(true/false)で、検証結果が得られるサンプル 抜粋
// 要素の取得 var element = document.getElementById("hoge"); // checkValidity() function myMethod() { // メソッドを実行 element.checkValidity() ; } // invalidイベントのコールバック関数 function callbackFunction(event) { // ... } // invalidイベントを設定 element.addEventListener("invalid", callbackFunction) ; </script>
■ Bootstrap4 による検証処理あれこれ
検証結果をクリアにする
例えば、モーダル画面にフォームがあって、エラーが発生させ、 その後、キャンセルボタンで押下し、モーダルを閉じる。 再度、モーダル画面を開いたときに、エラーがそのまま残っていた。 モーダル画面を再表示する前に、検証エラー結果をクリアしたい解決案
http://cccabinet.jpn.org/bootstrap4/components/forms
より抜粋 ~~~~~~~~~~~~~ フォームの外観をリセットするには(例:AJAXを使用した動的フォーム送信の場合)、 提出後に再び <form> から .was-validated クラスを削除する。 ~~~~~~~~~~~~~ // エラーのクリア $(sampleForm).removeClass("was-validated");