AngularJS same-as directive

For 'confirm password' fields

by Alex

HTML

<script src="http://code.angularjs.org/1.0.0rc10/angular-1.0.0rc10.js"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<body ng-app='MyApp' ng-controller='MainCtrl' class='container'>
<div class='row span4'>
  <form name='form' autocomplete='off'>

    <div class='control-group'>
      <label for='password'>
        Password
      </label>
      <div class='controls'>
        <input type='password' id='password' required name='password' ng-model='password'>
        <span class='help-inline' ng-show='form.password.$valid'>
          <i class='icon-ok'></i>
        </span>
      </div>
    </div>

    <div class='control-group'>
      <label for='password_confirmation'>
        Confirm password
      </label>
      <div class='controls'>
        <input type='password' id='password_confirmation' required name='password_confirmation' same-as='password' ng-model='password_confirmation'>
        <span class='help-inline' ng-show='form.password_confirmation.$valid'>
          <i class='icon-ok'></i>
        </span>
      </div>
    </div>

    <div class='form-actions'>
      <button class='btn btn-large btn-primary' ng-disabled='!form.$valid'>Create account</button>
    </div>
  </form>
</div>
</body>

CSS

body { padding-top: 20px; padding-left: 20px; }
input.ng-pristine.ng-invalid { border: dashed 2px red; }
input.ng-dirty.ng-invalid { border: solid 2px red; }

input.ng-dirty.ng-valid { border: solid 2px green; }

JavaScript

angular.module('MyApp', []).
controller('MainCtrl', ['$scope', function($scope) {
  $scope.password;
  $scope.password_confirmation;
}]).
directive('sameAs', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        if (viewValue === scope[attrs.sameAs]) {
          ctrl.$setValidity('sameAs', true);
          return viewValue;
        } else {
          ctrl.$setValidity('sameAs', false);
          return undefined;
        }
      });
    }
  };
});