2014-06-17 111 views
8

我有一個用於自定義驗證的指令(驗證用戶名尚不存在)。驗證使用$ http服務向服務器詢問用戶名是否存在,所以返回是一個承諾對象。這對驗證非常有用。該表單是無效的,並且包含myform。當用戶名已被佔用時,$ error.usernameVerify。但是,user.username總是未定義的,所以它打破了我的ng-model指令。我認爲這可能是因爲.success中的函數正在創建它自己的作用域,並且控制器$ scope上沒有使用返回值。我如何解決這個問題,以便ng-model綁定仍然有效?在AngularJS自定義驗證指令中調用異步服務

commonModule.directive("usernameVerify", [ 
    'userSvc', function(userSvc) { 
     return { 
      require: 'ngModel', 
      scope: false, 
      link: function(scope, element, attrs, ctrl) { 
       ctrl.$parsers.unshift(checkForAvailability); 
       ctrl.$formatters.unshift(checkForAvailability); 

       function checkForAvailability(value) { 
        if (value.length < 5) { 
         return value; 
        } 
        // the userSvc.userExists function is just a call to a rest api using $http 
        userSvc.userExists(value) 
         .success(function(alreadyUsed) { 
          var valid = alreadyUsed === 'false'; 
          if (valid) { 
           ctrl.$setValidity('usernameVerify', true); 
           return value; 
          } 
          ctrl.$setValidity('usernameVerify', false); 
          return undefined; 
         }); 
       } 
      } 
     } 
    } 
]); 

這裏是我的模板:

<div class="form-group" ng-class="{'has-error': accountForm.username.$dirty && accountForm.username.$invalid}"> 
    <label class=" col-md-3 control-label">Username:</label> 
    <div class="col-md-9"> 
     <input name="username" 
       type="text" 
       class="form-control" 
       ng-model="user.username" 
       ng-disabled="user.id" 
       ng-minlength=5 
       username-verify 
       required /> 
     <span class="field-validation-error" ng-show="accountForm.username.$dirty && accountForm.username.$error.required">Username is required.</span> 
     <span class="field-validation-error" ng-show="accountForm.username.$dirty && accountForm.username.$error.minlength">Username must be at least 5 characters.</span> 
     <span class="field-validation-error" ng-show="accountForm.username.$dirty && accountForm.username.$error.usernameVerify">Username already taken.</span> 
    </div> 
</div> 

回答

4

爲了得到這個工作,我需要添加「返回值」;異步調用之外。下面的代碼。

commonModule.directive("usernameVerify", [ 
    'userSvc', function(userSvc) { 
     return { 
      require: 'ngModel', 
      scope: false, 
      link: function(scope, element, attrs, ctrl) { 
       ctrl.$parsers.unshift(checkForAvailability); 
       ctrl.$formatters.unshift(checkForAvailability); 

       function checkForAvailability(value) { 
        if (value.length < 5) { 
         return value; 
        } 
        userSvc.userExists(value) 
         .success(function(alreadyUsed) { 
          var valid = alreadyUsed === 'false'; 
          if (valid) { 
           ctrl.$setValidity('usernameVerify', true); 
           return value; 
          } 
          ctrl.$setValidity('usernameVerify', false); 
          return undefined; 
         }); 
        // Below is the added line of code. 
        return value; 
       } 
      } 
     } 
    } 
]); 
+1

這是不正確。查看http://blog.brunoscopelliti.com/form-validation-the-angularjs-way –

+0

這種方法的問題是,checkForAvailability函數將立即返回(與您的值),因爲userExists函數返回一個承諾,將稍後再履行。 –

16

角有$ asyncValidators的專用陣列正是這個情況:

看到https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) { 
var value = modelValue || viewValue; 

// Lookup user by username 
return $http.get({url:'/api/users/' + value}). 
    then(function resolved() { 
    //username exists, this means validation fails 
    return $q.reject('exists'); 
    }, function rejected() { 
    //username does not exist, therefore this validation passes 
    return true; 
    }); 
}; 
+6

注意:這是從Angular 1.3.0開始提供的 –