angularjsangularjs-validation

Why does adding additional AngularJS validation directives cause $asyncValidators to run multiple times?


Why does adding additional AngularJS validation directives cause $asyncValidators to run multiple times on page load?

I created a custom directive which implements $asyncValidators. This is the basic structure of that custom directive:

myApp.directive('userSaved',['$q','userLookup',function($q, userLookup){
return {
  restrict: 'A',
  require: 'ngModel',
  link: function(scope, elem, attrs, ctrl){
    ctrl.$asyncValidators.userSaved = function(modelValue, viewValue) {
      // do stuff 
    }
  }
}
}]);

The controller initializes the tailNumber model value like this:

$scope.tailNumber = 'N33221';

This is the html where the user-saved directive runs 3 times on page load:

<input ng-model="tailNumber" name="tailNumber"   user-saved 
    ng-minlength="2"   ng-pattern="/^[A-z][a-zA-Z0-9]*$/" >

When I remove ng-minlength="2" then the user-saved directive runs twice on page load (2 times). This is the html with ng-minlength="2" removed:

<input ng-model="tailNumber" name="tailNumber"   user-saved 
    ng-pattern="/^[A-z][a-zA-Z0-9]*$/" >

When I remove ng-pattern="/^[A-z][a-zA-Z0-9]*$/" then the user-saved directive only runs 1 time. This is the html after removing ng-pattern="/^[A-z][a-zA-Z0-9]*$/"

<input ng-model="tailNumber" name="tailNumber" user-saved >

Why does my function registered with $asyncValidators run an additional time for each additional ng validator attached to the form element?

My custom directive is an expensive $http call, and I prefer my custom directive only run once on page load. Is it possible to use all of these ng validators and while only running my async validator function one time instead of 3 times on page load?


Solution

  • This is because validation directives like ngMaxlength, ngPattern invoke an initial validation cycle with a call to ngModelController.$validate().

    This causes all the validation directive to run their validation logic, including the async validators.

    One way to prevent the redundant $http calls, and in fact it is a good practice anyway, is to cache the validation result for each input.