I’m having a go at learning AngularJS, it’s been something I’ve used on and off for a while, but I’ve never had the chance to study it properly. I decided to work on a small project at the same time so that what I was reading would sink in.

One thing my project needed was a change password form. Now I used the handy in-built directives required and ng-minlength to ensure they entered something sensible, but there’s nothing built in for checking that you’ve typed the same password in the second time.

Not a big deal really, initially I implemented directive something like this:

<label for="newPassword">New Password</label>
<input type="password" name="newPassword" ng-model="password.new"
       ng-minlength="6" required />

<label for="newPasswordConfirm">Confirm New Password</label>
<input type="password" name="newPasswordConfirm"
       ng-model="password.confirm" ng-minlength="6"
       value-matches="password.new" required />
directive('valueMatches', ['$parse', function ($parse) {
  return {
    require: 'ngModel',
      link: function (scope, elm, attrs, ngModel) {
        var originalModel = $parse(attrs.valueMatches),
            secondModel = $parse(attrs.ngModel);
        // Watch for changes to this input
        scope.$watch(attrs.ngModel, function (newValue) {
          ngModel.$setValidity(attrs.name, newValue === originalModel(scope));
        });
        // Watch for changes to the value-matches model's value
        scope.$watch(attrs.valueMatches, function (newValue) {
          ngModel.$setValidity(attrs.name, newValue === secondModel(scope));
        });
      }
    };
  }]);

And it worked fine, have a play.

… oh, but I wanted to confirm the user’s existing password first, and I wanted to check the new password was different. Now we can’t re-use the value-matches directive even though it’s bloody similar so perhaps a refactor is in order.

Then it occurred to me, why not just use AngularJS’ expressions?! I ended up with something like this:

<label for="oldPassword">Old Password</label>
<input type="password" name="oldPassword" ng-model="password.old" required />

<label for="newPassword">New Password</label>
<input type="password" name="newPassword" ng-model="password.new"
       validation-check="password.old != password.new"
       ng-minlength="6" required />

<label for="newPasswordConfirm">Confirm New Password</label>
<input type="password" name="newPasswordConfirm"
       ng-model="password.confirm" ng-minlength="6"
       validation-check="password.new == password.confirm" required />
directive('validationCheck', ['$parse', function ($parse) {
  return {
    require: 'ngModel',
    link: function (scope, elm, attrs, ngModel) {
      var check = $parse(attrs.validationCheck);

      // Watch for changes to this input
      scope.$watch(check, function (newValue) {
        ngModel.$setValidity(attrs.name, newValue);
      });
    }
  };
}]);

It still works fine, check it out, the directive is much simpler, and now, as a bonus, it’s possible to re-use the directive for other form validation tasks in the future.

Cheers, Dave.