Angularjs setValidity causing modelValue to not update

angularjs, angularjs-directive, validation

Solution

It looks like maybe using $setValidity is not the way to go here. I found this question that proposes a different solution, using $validators and $validate(), and this is working for me great. The new code looks like this:

directive('match', function () {
  return {
    require: 'ngModel',
    restrict: 'A',
    scope: {
      match: '='
    },
    link: function(scope, elem, attrs, ngModel) {
      scope.$watch('match', function(pass){
        ngModel.$validate();
      });
      ngModel.$validators.match = function(modelValue, viewValue){
        var value = modelValue || viewValue;
        var match = scope.match;
        return value === match;
      };
    }
  };
});

Problem

I'm having some basic trouble with a form. Here's what I did. I snagged this cool looking directive from here: https://github.com/TheSharpieOne/angular-input-match It looks like this: ``` directive('match', function () { return { require: 'ngModel', restrict: 'A', scope: { match: '=' }, link: function(scope, elem, attrs, ngModel) { scope.$watch(function() { return (ngModel.$pristine && angular.isUndefined(ngModel.$modelValue)) || scope.match === ngModel.$viewValue; }, function(currentValue, previousValue) { ngModel.$setValidity('match', currentValue); }); } }; }); ``` Essentially, this directive watches the element it is attached to's model value, and compares it to the model value in the match attribute. So...for example, below we're watching to see if both passwords match: ``` Password: <input ng-model="password" type="password" /> Confirm: <input ng-model="passwordConfirm" type="password" match="password" /> ``` The directive seems to be working, in that it sets ng-valid-match and ng-invalid-match appropriately. However, once it is set to invalid, the passwordConfirm model never gets updated again. I've done a ton of console.loggin, looking at ngModel in the directive, and here is what it looks like when both passwords match: ``` Constructor {$viewValue: "asdf", $modelValue: undefined, $validators: Object, $parsers: Array[0], $formatters: Array[0]…} $$debounceViewValueCommit: function (trigger, revalidate) { $$invalidModelValue: "asdf" $$lastCommittedViewValue: "asdf" $$runValidators: function (modelValue, viewValue) { $$validityState: ValidityState $$writeModelToScope: function () { $commitViewValue: function (revalidate) { $dirty: true $error: Object $formatters: Array[0] $invalid: false $isEmpty: function (value) { $modelValue: undefined $name: "passwordConfirmation" $parsers: Array[0] $pristine: false $render: function () { $rollbackViewValue: function () { $setPristine: function () { $setTouched: function () { $setUntouched: function () { $setValidity: function (validationErrorKey, isValid) { $setViewValue: function (value, trigger, revalidate) { $touched: true $untouched: false $valid: true $validate: function () { $validators: Object $viewChangeListeners: Array[0] $viewValue: "asdf" __proto__: Object ``` Note that the $viewValue is correct, but the $modelValue is listed as undefined and $invalidModelValue still has a value. Here's what the html looks like, again when both passwords match: ``` <input type="password" class="form-control ng-isolate-scope ng-dirty ng-valid-required ng-valid ng-valid-match ng-touched" id="passwordConfirmation" name="passwordConfirmation" placeholder="Confirm your password" ng-model="passwordConfirmation" required="" match="password" style=""> ``` Am I missing something somewhere? I've been running in circles for hours.

Original source