<!doctype html>
<html lang="en">
  <meta charset="UTF-8">
  <title>Angular Form Validation Demo</title>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.min.js"></script>
  <script src="controller.js"></script>
  <link rel="stylesheet" type="text/css" href="style.css">

<body ng-app="FormValidationExample">
<div ng-controller="ctrlForm">
  <form name="myForm" novalidate>
    <div class="input-item">
      <label for="txtEmail">Your email</label><br>
      <input type="text" name="email" id="txtEmail" class="text-box" ng-model="email" email-regex required custom-focus />
      <div class="error-wrapper" ng-show="myForm.email.$dirty && myForm.email.$invalid && !myForm.email.$focused">
        <span ng-show="myForm.email.$error.required">Email is required</span>
        <span ng-show="myForm.email.$error.emailregex">Please enter a valid email address</span>

    <div class="input-item">
      <label for="interests">What interests you?</label><br>
      <textarea name="interests" id="interests" class="text-box" ng-model="interests" ng-maxlength="255" ng-minlength="10" required custom-focus></textarea>
      <div class="error-wrapper" ng-show="myForm.interests.$dirty && myForm.interests.$invalid">
        <span ng-show="myForm.interests.$error.maxlength">Must be less than 255 characters</span>
        <span ng-show="myForm.interests.$error.minlength && !myForm.interests.$focused">Must be more than 10 characters</span>
    <div class="input-item">
      <label for="txtPets">How many pets do you have?</label><br>
      <input type="number" min="0" pattern="-?\d*" name="pets" id="txtPets" class="text-box" ng-model="pets" required custom-focus />
      <div class="error-wrapper" ng-show="myForm.pets.$dirty && myForm.pets.$invalid">
        <span ng-show="myForm.pets.$error.required && myForm.pets.$dirty">Please enter 0 or more</span>
        <span ng-show="myForm.pets.$error.number && myForm.pets.$dirty">Must be numeric</span>
        <span ng-show="myForm.pets.$error.min && myForm.pets.$dirty">You can't have negative pets!</span>
        <span ng-show="myForm.pets.$error.pattern && myForm.pets.$dirty">Must be an integer</span>
    <!-- Bonus check-all demo! -->
    <div class="input-item">
      <label>What are you reading this for?</label>
      <span class="inline-note" ng-show="checkedCount > 0">{{checkedCount}} selected</span><br>
      <input type="checkbox" class="select-all" ng-model="checkboxes_motives.checked" ng-change="selectAllMotives(checkboxes_motives.checked)" /><br>
      <input type="checkbox" name="motivation" id="play" ng-model="checkboxes_motives.items['play']" 
             ng-change="updateCheckedCount(checkboxes_motives.items['play'])" />
      <label for="play">Play</label>
      <input type="checkbox" name="motivation" id="work" ng-model="checkboxes_motives.items['work']" 
             ng-change="updateCheckedCount(checkboxes_motives.items['work'])" />
      <label for="work">Work</label>

    <input type="submit" value="Submit" ng-disabled="myForm.$invalid" />

.input-item {
  margin: 18px 0;

.error-wrapper {
  display: inline-block;
  color: red;

.inline-note {
  margin-left: 20px;
  color: blue;

.text-box {
  width: 200px;

.text-box.ng-valid:not(.custom-focused) {
  border-color: green;

.text-box.ng-invalid.ng-dirty:not(.custom-focused) {
  border-color: red;
Not only does Angular allow you to validate user input using built-in and custom directives, it also automatically furnishes your elements with helpful CSS classes.

Visit http://info.easydynamics.com/blog/angularjs-form-validation to learn about Angular form validation. 
Visit http://info.easydynamics.com/blog/write-custom-angular-directives to learn how to write custom directives.
var myApp = angular.module('FormValidationExample', []);

myApp.controller('ctrlForm', ['$scope', function($scope) {
  $scope.checkboxes_motives = { 'checked': false, items: {} };
  $scope.choices = ['work', 'play'];
  $scope.checkedCount = 0;
  $scope.selectAllMotives = function(checked) {
    angular.forEach($scope.choices, function (motive) {
      var isChecked = $scope.checkboxes_motives.items[motive];
      $scope.checkboxes_motives.items[motive] = checked;
      if (checked != isChecked) {
  $scope.updateCheckedCount = function (checked) {
    if (checked) $scope.checkedCount++;
    else $scope.checkedCount--;
// Attaches event listeners
myApp.directive('customFocus', [function() {
  var FOCUS_CLASS = "custom-focused"; //Toggle a class and style that!
  return {
    restrict: 'A', //Angular will only match the directive against attribute names
    require: 'ngModel', 
    link: function(scope, element, attrs, ctrl) {
      ctrl.$focused = false;
      element.bind('focus', function(evt) {
        scope.$apply(function() {ctrl.$focused = true;});
      }).bind('blur', function(evt) {
        scope.$apply(function() {ctrl.$focused = false;});

// Adds custom validation test to element
myApp.directive('emailRegex', [function (ngModel) {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function (scope, linkElement, linkAttributes, controller) {
      var regex = /^[a-zA-Z0-9-\_]+[a-zA-Z0-9-_\.]*(\.[a-zA-Z0-9-_]+)*([a-zA-Z0-9]+)@[a-zA-Z]+[0-9a-zA-Z-\.]*[0-9a-zA-Z]+\.[a-zA-Z]{2,5}$/;
      function checkValidity(value) {
        var valid = true;
        // This directive should consider an empty value to be valid
        // because the required test, if specified, occurs separately
        if (value != null && value.length > 0) {
          valid = regex.test(value);

        return valid;

      controller.$parsers.unshift(function (value) {
        // View to model
        var valid = checkValidity(value);
        // Note "emailregex" instead of "emailRegex" - should be all lowercase
        // This allows "$error.emailregex" to work in the DOM
        controller.$setValidity('emailregex', valid);

        // Only return the value to the model if it's valid
        return valid ? value : undefined;

      controller.$formatters.unshift(function (value) {
        // Model to view
        controller.$setValidity('emailregex', checkValidity(value));

        // Return the value regardless of validity,
        // otherwise nothing will appear on the DOM
        return value;