2014-06-17 9 views
8

Ho una direttiva per la convalida personalizzata (verificare che un nome utente non esista già). La convalida utilizza il servizio $ http per chiedere al server se il nome utente esiste, quindi il ritorno è un oggetto promessa. Questo funziona fantastico per la convalida. Il modulo non è valido e contiene myform. $ Error.usernameVerify quando il nome utente è già in uso. Tuttavia, user.username è sempre indefinito, quindi sta infrangendo la mia direttiva ng-model. Penso che questo sia probabilmente dovuto al fatto che la funzione in .success sta creando il proprio ambito e il valore restituito non è utilizzato sui controller $ scope. Come posso risolvere questo problema in modo che l'associazione ng-model funzioni ancora?Chiamare il servizio asincrono nella direttiva di convalida personalizzata 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; 
         }); 
       } 
      } 
     } 
    } 
]); 

Ecco il mio modello:

<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> 

risposta

4

Al fine di ottenere questo lavoro, avevo bisogno di aggiungere "valore di ritorno"; al di fuori della chiamata asincrona. Codice sotto.

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

Questo non è corretto. Controlla http://blog.brunoscopelliti.com/form-validation-the-angularjs-way –

+0

Il problema con questo approccio è che la funzione checkForAvailability ritorna (con il tuo valore) immediatamente, poiché le funzioni userExists restituiscono una promessa che essere adempiuto più tardi. –

16

angolare ha una gamma dedicata di $ asyncValidators proprio per questa situazione:

vedere 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

Nota: disponibile da Angular 1.3.0 –

Problemi correlati