AngularJS Form Validation with Bootstrap Decorations

Creates a "UserValidation" module with validation directives such as valid-username and valid-password. Sets properties on the scope to turn errors on and off. Turns on errors progressively - ie, one error per field at a time. For the most part, uses angular's built in form validation structure. Does not use built in required directive because I wanted to sequence the errors. (there must be a way to use it and still do this.) Am not pleased with "formAllGood" directive, but "myform.$valid" doesn't work for me, the submit button hides & unhides as the user fills the form out. http://thomporter.com

HTML

<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css">
<div ng-app="myapp">
  <form name="myform" class="form form-horizontal" ng-controller="myappCtrl" novalidate>
    <legend>Angular User Validation with Bootstrap Decorations</legend>
    <div class="control-group" ng-class="{error:!myform.username.$valid}">
      <label for="inputUsername" class="control-label">Username:</label>
      <div class="controls">
        <input type="text" id="inputUsername" name="username" ng-model="username" valid-username />
        <div class="help-inline">
          <span ng-show="!!myform.username.$error.isBlank">Username Required.</span>
          <span ng-show="!!myform.username.$error.invalidChars">Username must contain letters &amp; spaces only.</span>
          <span ng-show="!!myform.username.$error.invalidLen">Username must be 5-20 characters.</span>
        </div>
      </div>
    </div>
    <div class="control-group" ng-class="{error:!myform.password.$valid}">
      <label for="inputPassword" class="control-label">Password:</label>
      <div class="controls">
        <input type="text" id="inputPassword" name="password" ng-model="password" valid-password />
        <div class="help-inline">
          <span ng-show="!!myform.password.$error.isBlank">Password Required.</span>
          <span ng-show="!!myform.password.$error.isWeak">Must contain one upper &amp; lower case letter and a non-letter (number or symbol.)</span>
          <span ng-show="!!myform.password.$error.invalidLen">Must be 8-20 characters.</span>
        </div>
      </div>
    </div>
    <div class="control-group" ng-class="{error:!myform.password_c.$valid}">
      <label for="password_c" class="control-label">Confirm Password:</label>
      <div class="controls">
        <input type="text" id="password_c" name="password_c" ng-model="password_c" valid-password-c />
        <div class="help-inline">
          <span...

JavaScript

var app = angular.module('myapp', ['UserValidation']);

myappCtrl = function($scope) {
  $scope.formAllGood = function() {
    return ($scope.usernameGood && $scope.passwordGood && $scope.passwordCGood)
  }

}

angular.module('UserValidation', []).directive('validUsername', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        // Any way to read the results of a "required" angular validator here?
        var isBlank = viewValue === ''
        var invalidChars = !isBlank && !/^[A-z0-9]+$/.test(viewValue)
        var invalidLen = !isBlank && !invalidChars && (viewValue.length < 5 || viewValue.length > 20)
        ctrl.$setValidity('isBlank', !isBlank)
        ctrl.$setValidity('invalidChars', !invalidChars)
        ctrl.$setValidity('invalidLen', !invalidLen)
        scope.usernameGood = !isBlank && !invalidChars && !invalidLen

      })
    }
  }
}).directive('validPassword', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue) {
        var isBlank = viewValue === ''
        var invalidLen = !isBlank && (viewValue.length < 8 || viewValue.length > 20)
        var isWeak = !isBlank && !invalidLen && !/(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z])/.test(viewValue)
        ctrl.$setValidity('isBlank', !isBlank)
        ctrl.$setValidity('isWeak', !isWeak)
        ctrl.$setValidity('invalidLen', !invalidLen)
        scope.passwordGood = !isBlank && !isWeak && !invalidLen

      })
    }
  }
}).directive('validPasswordC', function() {
  return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {
      ctrl.$parsers.unshift(function(viewValue, $scope) {
        var isBlank = viewValue === ''
        var noMatch = viewValue != scope.myform.password.$viewValue
        ctrl.$setValidity('isBlank', !isBlank)
        ctrl.$setValidity('noMatch', !noMatch)
       ...