自定義表單驗證

  <input type="text" ng-model='li' fv>


/*
  要使用link的第四個參數有兩個必要條件
    1 require存在
    2 必須以屬性或類名的方式存在於一個input標籤中,而且該標籤有ng-model屬性;

 */
  app.directive('fv', function(){
    return {
      restrict: 'EA',
      require: 'ngModel',
      link: function(scope, ele, attr, ngmodel){
        console.info('lifei',ngmodel);
      }
    }
  })

一下是輸出的ngModel裏面的內容
  1. NgModelController
    1. $asyncValidators:Object     異步驗證
    2. $commitViewValue:()
    3. $dirty:false                                  是否修改
    4. $error:Object                                錯誤
    5. $formatters:Array[1]                      數據格式化的管道函數數組
    6. $invalid:false                                是否不合法
    7. $isEmpty:(value)                               是不是空
    8. $modelValue:undefined                     當前的valud值
    9. $name:""                                                                               input的name
    10. $options:null 
    11. $parsers:Array[0]                                                                 設置表單合法性的管道函數數組
    12. $pending:undefined
    13. $pristine:true
    14. $render:()
    15. $rollbackViewValue:()
    16. $setDirty:()                                                                          設置是否已修改
    17. $setPristine:()
    18. $setTouched:()
    19. $setUntouched:()
    20. $setValidity:setValidity(validationErrorKey, state, controller)         設置表單的某一驗證的合法性
    21. $setViewValue:(value, trigger)                         設置valud值
    22. $touched:false
    23. $untouched:true
    24. $valid:true                                                驗證時候合法
    25. $validate:()
    26. $validators:Object                                  同步驗證
    27. $viewChangeListeners:Array[0]               當value值改變時,執行的管道函數數組
    28. $viewValue:undefined               當前input的ng-model的值
    29. __proto__:Object

<form name='myForm'>
  <input type="text" name='li1' ng-model="lifei1">
  <input type="text" name="li2" pwd-match='myForm.li1' ng-model='lifei2'>
</form>ajax


  
//判斷兩次輸入的密碼是否相同
app.directive('myPwdMatch', [function(){ return {

//若是用link的第四個參數ctrl,必須有require:'ngModel',和類型必須是屬性 restrict:
"A", require: 'ngModel', link: function(scope,element,attrs,ctrl){

//attrs.myPwdMatch的屬性值是formName.input1Name字符串,用scope.$eval()來解析字符串,獲取對應的input1Name對象
var tageCtrl = scope.$eval(attrs.myPwdMatch);

//添加自定義表單驗證的合法性 tageCtrl.$parsers.push(
function(viewValue){

//設置當前input的pwdmatch的合法性,若是input1的value值 等於當前input的value值,認爲他合法 ctrl.$setValidity(
'pwdmatch', viewValue == ctrl.$viewValue); return viewValue; });

//當前input添加表單驗證的合法性 ctrl.$parsers.push(
function(viewValue){ if(viewValue == tageCtrl.$viewValue){ ctrl.$setValidity('pwdmatch', true); return viewValue; } else{ ctrl.$setValidity('pwdmatch', false); return undefined; } }); } }; }]);

 

也就是說: $validators和$asyncValidators這兩個管道是$parsers管道函數數組裏面的其中兩個比較特殊的管道;json

*5. $validatorsapi

一個json對象.數組

{
   validateName: function(modelValue,viewValue){
       return ...
   }
}

當$setViewValue(value)被賦值給$modelValue以前,會通過$parsers管道,通過$parsers管道時,就會通過這個$validators管道.其中validateName是驗證的名字,函數是這個驗證的方法,其中的參數modelValue和viewValue就是$modelValue和$viewValue,若是返回值是true,則經過validateNamepromise

驗證,若是返回值是false,則沒有經過validateName驗證,若是沒有經過validateName驗證,$error.validateName就會爲true.這就是angular內部驗證表單項的原理.cookie

eg: 自定義一個驗證規則,輸入內容中必須包含數字併發

<div class="alert alert-danger" role="alert" ng-show="myForm.myWidget.$error.validCharacters">
    <strong>Oh!</strong> 不符合自定義的驗證規則!
</div>
ngModel.$validators.validCharacters = function(modelValue, viewValue) {
    var value = modelValue || viewValue;
    return /[0-9]+/.test(value);
};

 

*6.$asyncValidatorsapp

一個json對象.用來處理異步驗證(好比一個http請求). 異步

{
   validateName: function(modelValue,viewValue){
       return promise
   }
}

其中validateName是驗證的名字,函數是這個驗證的方法,其中的參數modelValue和viewValue就是$modelValue和$viewValue,返回值必須是一個promise對象,若是這個promise對象傳遞給它下一個.then方法失敗通知,則不經過validateName驗證,若是這個promise對象傳遞給它下一個.then方法成功通知,則表示經過validateName驗證.當異步驗證開始執行的時候,全部的異步驗證都是平行併發的.只有當全部的驗證都經過時,數據模型纔會被同步更新.只要有一個異步驗證沒有完成,這個驗證名就會被放到ngModelController的$pending屬性中.另外,全部的異步驗證都只會在全部的同步驗證經過之後纔開始.async

核心代碼:

<input validate-name type="text" name="myWidget" ng-model="userContent" ng-model-options="{updateOn:'blur'}" class="form-control" required uniqueUsername>

<div class="alert alert-danger" role="alert" ng-show="myForm.myWidget.$error.uniqueUsername">
      <strong>Oh!</strong> 已經存在的用戶名!
</div>
複製代碼
app.directive('validateName',function($http,$q){
    return {
        restrict:'A',
        require:'?^ngModel',
        link:function(scope,iele,iattr,ctrl){
            ctrl.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
                var value = modelValue || viewValue;
                // 異步驗證用戶名是否已經存在
                return $http.get('/api/users/' + value).
                then(function resolved(res) {
                    if(res.data){
                        //用戶名已經存在,驗證失敗,給下一個promise傳遞失敗通知.
                        return $q.reject('res.data');
                    }
                    else {
                        //用戶名不存在,驗證成功.
                        return true
                    }

                }, function rejected() {
                        //請求失敗
                })
            };
        }
    }
});
複製代碼

 

一個指令用於異步驗證是否重命名:

    /*異步驗證是否重命名
    *     例子: <input type="text"   name="name" ng-model="form.name" create-head='{"url":"app_name/used","param":"app_name={value}"}'/>
    
    1 自定義驗證: require,屬性
        1 restrict必須是屬性,requre必須是'ngModel'
    2 進行異步驗證設置 $asyncValidators = {驗證名: 驗證函數}
    2 獲取請求的url,用於ajax請求
        1 用先把input標籤上的createHead屬性的json字符串獲取
        2 再用angular.formJson()解析成json對象
        3 再用string.replace(string,value),把佔位符"{value}" 替換成input的modelValue值(scope上的值)
        4 用commonService來拼接url
    3 建立一個defered對象,用來返回狀態
        1 用var a = $q.defer()建立
        2 a.reject()表示拒絕
        3 a.resolve()表示成功
    4 $http請求
        1 method,url,headers
        2 返回的是一個promise對象
    5 分狀況驗證
        1 若是成功,說明找到了,命名重複,驗證不經過,返回a.reject();
        2 若是404,說明沒找到了,命名不重複,驗證經過,返回a.resolve();
        3 若是是其餘狀況,不能肯定,是否重命名,按驗證不經過算,趕回a.reject();
    6 返回一個promise對象
    * */

app.directive("createHead", ["$q", "$http", "$cookies", "AppConfig", "commonService", function($q, $http, $cookies, AppConfig, commonService){
    return{
        restrict:"A",
        require:"ngModel",
        scope:{
            version:"="
        },
        link:function(scope,ele,attrs,ctl){
            console.info("ctrl",ctl);
            //格式demo:  create-head='{"url":"app_name/used","param":"app_name={value}"}'
            ctl.$asyncValidators.checkasync = function(modelValue,viewValue){
                var d = $q.defer();
                //angular.formJson()方法能夠把json字符串解析成json對象;
                var _a = angular.fromJson(attrs.createHead);

                _a.url = _a.url.replace("{value}",modelValue);
                if(_a.param){
                    _a.param = _a.param.replace("{value}",modelValue);
                }

                $http({
                    method:"HEAD",
                    url:commonService.getServerAuthUrl(_a.url,_a.param?_a.param:null),
                    headers:{
                        "Authorization": $cookies.get("token")
                    }
                }).then(function(e){
                    //200 已存在
                    d.reject();
                },function(e){
                    if(e.status==404){
                        //不存在
                        d.resolve();
                    }
                    else{
                        d.reject();
                    }
                });
                return d.promise;
            };
        }
    };
}]);
相關文章
相關標籤/搜索