雖然說AngularJS的實時表單驗證非常有用,非常高效方便,但是當用戶還沒有完成輸入時便彈出一個錯誤提示,這種體驗是非常糟糕的。
正常的表單驗證邏輯應該是在用戶提交表單后或完成當前字段中的輸入后,再提示驗證信息,這樣才是用戶友好的。下面就來看看如何實現
- 在表單提交后顯示驗證信息
- 在失焦后顯示驗證信息
在表單提交后顯示驗證信息
在用戶試圖提交表單時,你可以在作用域中捕獲一個submitted值,然后對表單內容進行驗證並顯示錯誤信息。
下面通過一個簡單的例子來說明,只在用戶提交表單時才顯示錯誤信息。在ng-show 指令中添加對submitted(判斷表單是否提交)的檢查,僅有當submitted的值為true(即表示表單已提交)同時該表單元素是處於$invalid狀態的時候,錯誤信息就會顯示出來
HTML代碼
<form name="registerForm" class="registerForm" novalidate ng-submit="register(user)"> <div class="title">歡迎注冊,和我們一起甜蜜生活</div> <div class="form-group " ng-class="registerForm.username.$invalid ? '' : 'has-success'"> <div class="input-group"> <div class="input-group-addon"><span class=" iconfont icon-register icon-phone"></span></div> <input type="text" name="username" class="form-control" placeholder="請輸入手機號碼" ng-model="user.username" maxlength="11" required ng-pattern="/1[3|5|7|8|][0-9]{9}/"/> </div> <div class="form-error" ng-show="registerForm.username.$invalid && submitted "> <span ng-show="registerForm.username.$error.required">手機號不能為空</span> <span ng-show="registerForm.username.$error.pattern">請輸入正確的手機號碼</span> </div> </div> <input type="submit" value="注冊" class="btn btn-register btn-tianmi"/> {{result}} </form>
Controller代碼
$scope.submitted = false $scope.register = function (user) { //表單正常提交 if($scope.registerForm.$valid){ //正常提交表單 } else{ $scope.submitted = true; } };
通過上面的方法,便可以實現用戶在有非法輸入的情況下提交表單,將顯示錯誤信息
在失焦后顯示驗證信息
要想保留用戶在輸入某個字段失焦后提示錯誤信息,需要實現一個ngFocus的指令,並在表單中添加該指令
ngFocus指令代碼
.directive('ngFocus', function () { var FOCUS_CLASS = "ng-focused"; return{ restrict:'A', require:'ngModel', link: function (scope, element, attrs,ctrl) { ctrl.$focused = false; element.bind('focus', function (evt) { element.addClass(FOCUS_CLASS); scope.$apply(function () { ctrl.$focused = true; }); }).bind('blur', function () { element.removeClass(FOCUS_CLASS); scope.$apply(function(){ ctrl.$focused = false; }) }) } } })
接下來將ngFocus指令添加到input的元素上就可以使用該指令,依然用上面的表單例子
<form name="registerForm" class="registerForm" novalidate ng-submit="register(user)"> <div class="title">歡迎注冊,和我們一起甜蜜生活</div> <div class="form-group " ng-class="registerForm.username.$invalid ? '' : 'has-success'"> <div class="input-group"> <div class="input-group-addon"><span class=" iconfont icon-register icon-phone"></span></div> <input type="text" name="username" class="form-control" placeholder="請輸入手機號碼" ng-model="user.username" maxlength="11" required ng-pattern="/1[3|5|7|8|][0-9]{9}/" ng-focus/> </div> <div class="form-error" ng-show="registerForm.username.$invalid && !registerForm.username.$focused "> <span ng-show="registerForm.username.$error.required">手機號不能為空</span> <span ng-show="registerForm.username.$error.pattern">請輸入正確的手機號碼</span> </div> </div> <input type="submit" value="注冊" class="btn btn-register btn-tianmi"/> {{result}} </form>
ngFocus指令給表單輸入字段的blur和focus添加了相應的行為,添加了一個名為ng-focused的類,並將$focused的值設置為true。這樣就可以通過判斷表單是否具有焦點來顯示錯誤信息
<div class="form-error" ng-show="registerForm.username.$invalid && !registerForm.username.$focused "> <span ng-show="registerForm.username.$error.required">手機號不能為空</span> <span ng-show="registerForm.username.$error.pattern">請輸入正確的手機號碼</span> </div>
當然了,在正常的情況下,我們一般是使用失焦后驗證+表單提交后驗證兩種方式相結合的形式來進行表單驗證。下面就通過一個完整的用戶注冊例子來顯示如果實現這種驗證方式。
HTMl代碼
<form name="registerForm" class="registerForm" novalidate ng-submit="register(user)"> <div class="title">歡迎注冊,和我們一起甜蜜生活</div> <div class="form-group " ng-class="registerForm.username.$invalid ? '' : 'has-success'"> <div class="input-group"> <div class="input-group-addon"><span class=" iconfont icon-register icon-phone"></span></div> <input type="text" name="username" class="form-control" placeholder="請輸入手機號碼" ng-model="user.username" maxlength="11" required ng-pattern="/1[3|5|7|8|][0-9]{9}/" ng-focus/> </div> <div class="form-error" ng-show="(registerForm.username.$invalid && registerForm.username.$dirty && !registerForm.username.$focused) || (registerForm.username.$invalid && submitted )"> <span ng-show="registerForm.username.$error.required">手機號不能為空</span> <span ng-show="registerForm.username.$error.pattern">請輸入正確的手機號碼</span> </div> </div> <div class="form-group row sms-code-row"> <div class="col-xs-6 input-sms-code"> <input type="text" value="" name="sms_code" class="form-control" ng-model="user.sms_code" placeholder="請輸入6位驗證碼" required ng-maxlength="6" maxlength="6"/> </div> <div class="col-xs-6 btn-sms-code"> <button type="button" class="btn btn-default btn-register btn-tianmi" ng-click="getVerifyCode(user.username)" ng-disabled="sms_code_status || registerForm.username.$invalid">{{sms_code_content}} </button> </div> <div class="clearfix"></div> <div class="form-error" ng-show="(registerForm.sms_code.$invalid && registerForm.sms_code.$dirty) ||(registerForm.sms_code.$invalid && submitted) "> <span ng-show="registerForm.sms_code.$error.required">請輸入驗證碼</span> </div> </div> <div class="form-group"> <div class="input-group"> <div class="input-group-addon"><span class=" iconfont icon-register icon-key"></span></div> <input type="password" name="password" ng-model="user.password" class="form-control" placeholder="請輸入登錄密碼" required ng-focus minlength="6" ng-pattern="/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$/"/> </div> <div class="form-error" ng-show="(registerForm.password.$invalid && registerForm.password.$dirty && !registerForm.password.$focused) || (registerForm.password.$invalid && submitted)"> <span ng-show="registerForm.password.$error.minlength">密碼不能少於6位</span> <span ng-show="registerForm.password.$error.pattern">密碼必須由數字和字母組成</span> <span ng-show="registerForm.password.$error.required">密碼不能為空</span> </div> </div> <div class="form-group"> <div class="input-group"> <div class="input-group-addon"><span class=" iconfont icon-register icon-key"></span></div> <input type="password" name="repeat_password" class="form-control" ng-model="user.repeat_password" ng-focus placeholder="請再次輸入密碼" required pw-check match="user.password"/> <!--<span class="iconfont icon-yonghu"></span>--> </div> <div class="form-error" ng-show="(registerForm.repeat_password.$invalid && registerForm.repeat_password.$dirty && registerForm.repeat_password.$focused) || (registerForm.repeat_password.$invalid && submitted)"> <span ng-show="registerForm.repeat_password.$error.required">密碼不能為空</span> <span ng-show="registerForm.$error.matchError">兩次密碼不一樣</span> </div> </div> <div class="form-group"> <div class="input-group"> <div class="input-group-addon"><span class=" iconfont icon-register icon-yonghu"></span></div> <input type="text" name="nick_name" class="form-control" ng-model="user.nick_name" placeholder="請輸入昵稱" minlength="2" maxlength="20" ng-focus ng-pattern="/^[a-zA-Z0-9\u0391-\uFFE5]{2,20}$/ " required/> </div> <div class="form-error" ng-show="(registerForm.nick_name.$invalid && registerForm.nick_name.$dirty && registerForm.nick_name.$focused) || (registerForm.nick_name.$invalid && submitted)"> <span ng-show="registerForm.nick_name.$error.required">昵稱不能為空</span> <span ng-show="registerForm.nick_name.$error.pattern">昵稱為2-20個字符,可由中文、字母和數字組成</span> </div> </div> <div class="checkbox"> <label> <input type="checkbox" name="protocol" ng-model="protocol" required> 同意 <a class="protocol" href="http://123.57.246.184/wordpress/?p=1941" target="_blank">添米用戶注冊協議</a> 和 <a class="protocol" href="http://123.57.246.184/wordpress/?p=1939" target="_blank">添米投資服務協議</a> </label> <div class="form-error" ng-show="!protocol && submitted"> <span>請先同意協議</span> </div> </div> <input type="submit" value="注冊" class="btn btn-register btn-tianmi"/> {{result}} </form>
controller代碼
$scope.submitted = false $scope.register = function (user) { //表單正常提交 if($scope.registerForm.$valid){ //正常提交表單 } else{ $scope.submitted = true; } };