CatalinM CatalinM - 2 months ago 14
AngularJS Question

Angular: force custom form validator to run on any field input

I've written a custom validator for a password field, in order to verify the following scenarios:


  • if user has id defined, then password is always valid (can be empty, meaning no change)

  • if user does not have id defined, then password must not be empty (new users must have a password)



Problem is, I have noticed the validator is run only when the user interacts with the field (unlike
required
which is run on any input apparently). This makes the form appear valid even if password empty for a new user. Once I interact with the password input, everything seems fine.

I have solved the business logic requirement through the poorly documented
ngRequired
directive, but I would really like to understand the issue regarding the custom validator in case I run into it again.

Answer

After giving up on this, I ran into the problem again and I could not find a workaround. Fortunatel, I found a solution:

When you make a custom validator you need to bind it to the model field, not the form field. This makes it validate correctly all the time (one can assume due to differences between $modelValue and $viewValue properties that are on the form field which fudges up things). Please see code below for reference:

<input type="password" class="form-control" id="confirmpass" name="confirmpass" placeholder="Repeat Password"
                       ng-model="controller.selectedUser.passwordRepeat"
                       compare-to="controller.selectedUser.password"/>

And custom validator:

angular.module("compareTo", []).directive("compareTo", function() {
   return {
       require: "ngModel",
       scope: {
       otherModelValue: "=compareTo"
   },
   link: function(scope, element, attributes, ngModel) {

       ngModel.$validators.compareTo = function(modelValue) {
           return modelValue == scope.otherModelValue;
       };

       scope.$watch("otherModelValue", function() {
           ngModel.$validate();
       });
   }
  };
  );
Comments