<!DOCTYPE html>
<html ng-app="demo">

<head>
  <script src="https://code.angularjs.org/1.3.0-rc.4/angular.js"></script>
  <script src="https://code.angularjs.org/1.3.0-rc.4/angular-messages.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>

<body ng-controller="ProfileController as profile">

  {{ profile.message }}

  <form name="profileForm" ng-submit="profile.submit(profileForm.$valid)" novalidate>

    <input type="number" name="favoriteNumber" ng-model="profile.number" required min="1" odd prime />

    <div ng-if="profileForm.favoriteNumber.$pending">
      Calculating....
    </div>
    <div ng-messages="profileForm.favoriteNumber.$error" ng-messages-include="messages.html" class="errors">
      <!-- overrides the min message from the include -->
      <span ng-message="min">Must be more than 1.</span>
    </div>


    <input type="submit" value="Save" />

  </form>


  <pre>
{{ profileForm | json }}
    </pre>
</body>

</html>
(function() {

  var app = angular.module("demo", ["ngMessages"]);

  app.controller("ProfileController", function() {
    var model = this;
    
    model.message = "";
    model.submit = function(valid) {
      if (valid) {
        model.message = "Your new number is " + model.number;
      } else {
        model.message = "Needs fixing!";
      }
    };
  });

  app.directive("odd", function() {
    return {
      restrict: "A",
      require: "ngModel",
      link: function(scope, element, attributes, ngModel) {
        ngModel.$validators.odd = function(modelValue) {
          return modelValue % 2 === 1;
        };
      }
    };
  });

  app.directive("prime", function($q, $timeout) {

    var isPrime = function(n) {
      if (n < 2) { 
        return false; 
      }

      for (var i = 2; i <= Math.sqrt(n); i++) {
        if (n % i === 0) {
          return false;
        }
      }
      return true;
    };

    return {
      restrict: "A",
      require: "ngModel",
      link: function(scope, element, attributes, ngModel) {
        ngModel.$asyncValidators.prime = function(modelValue) {
          var defer = $q.defer();
          $timeout(function(){
            if(isPrime(modelValue)) {
              defer.resolve();
            } else {
              defer.reject();
            }
          }, 2000);
          return defer.promise;
        }
      }
    };
  });

}());
.ng-invalid {
  border-color: red;
  border-width: 2px;
}

.ng-pending {
  border-color: white;
}

.errors {
  font-size:smaller;
  color:red;
}


body {
  font-family: sans-serif;
  font-size: 24px;
}
<span ng-message="required">Required!</span>
<span ng-message="min">Too small!</span>
<span ng-message="number">Must be a number!</span>
<span ng-message="odd">Odd numbers only!</span>
<span ng-message="prime">Prime numbers only!</span>
<!--  and so on, for all possible validation attributes -->