Angular: Passwords

by ud3323

HTML

<h3>Two ways of password validation</h3>

<form name="form">
  Password: <input type="password" ng:model="password" name="pwd" required />
  Confirm: <input type="password" ng:model="passwordConfirm" name="pwd2" password-validator="pwd" required/>
</form>

<ul>
<li ng:repeat="(name, e) in form.$error">
  {{name}}:
  <ul>
    <li ng:repeat="widget in e">{{widget.$name}}</li>
  </ul>
</li>
</ul>

<hr />

<form name="form2" form-pwd-validator="pwd pwd2">
  Password: <input type="password" ng:model="password" name="pwd" required ng:model-instant/>
    Confirm: <input type="password" ng:model="passwordConfirm" name="pwd2" required ng:model-instant /><br />
    Both these inputs have ng:model-instant, so they are updated immediately:<br />
    pwd = {{password}}<br />
    confirm = {{passwordConfirm}}<br />
</form>

<ul>
<li ng:repeat="(name, e) in form2.$error">
  {{name}}:
  <ul>
    <li ng:repeat="widget in e">{{widget.$name}}</li>
  </ul>
</li>
</ul>

CSS

.ng-invalid {
    border-color: red;
}

.ng-valid {
    border-color: green;
}

.ng-dirty {
    border-style: solid;
    border-width: 2px;
}

.ng-pristine {
    border-style: solid;
    border-width: 1px;
}

.errors {
    color: red;
}
h3 {
  font-size: 1.4em;
  font-weight: bold;
  margin-bottom: 15px;
}

JavaScript

var myApp = angular.module('myApp', []);

// directive on widget
myApp.directive('passwordValidator', [function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attr, ctrl) {
      // must be on the second password, when linking first one, the second one is not registered yet
      var pwdWidget = scope.form[attr.passwordValidator];

      ctrl.$parsers.push(function(value) {
        if (value === pwdWidget.$viewValue) {
          ctrl.$setValidity('MATCH', true);
          return value;
        }
        ctrl.$setValidity('MATCH', false);
      });

      pwdWidget.$parsers.push(function(value) {
        ctrl.$setValidity('MATCH', value === ctrl.$viewValue);
        return value;
      });
    }
  };
}]);

// directive on form
myApp.directive('formPwdValidator', [function() {
  return {
    require: 'form',
    link: {
      post: function(scope, elm, attr, form) {
        var ids = attr.formPwdValidator.split(' '),
            first = form[ids[0]],
            second = form[ids[1]];

        first.$parsers.push(function(value) {
          second.$setValidity('MATCH', value === second.$viewValue);
          return value;
        });

        second.$parsers.push(function(value) {
          if (value === first.$viewValue) {
            second.$setValidity('MATCH', true);
            return value;
          }
          second.$setValidity('MATCH', false);
        });
      }
    }
  }
}]);