<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
  <meta charset="utf-8">

  <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.css">
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.js"></script>
  <style>
    .formInput.ng-valid {border: 1px solid green;}
    .formInput.ng-invalid {background-color: #FF6666;}
    .formInput.ng-pristine {border: 1px solid blue; background-color: transparent;}
  </style>
</head>

<body ng-controller="AppCtrl">
  <script>
    var app = angular.module('app', []);

    app.controller('AppCtrl', function($scope) {
      $scope.person = {};
    });
  </script>
  <script src="inputEmail.js"></script>
  <script src="InputEmailCtrl.js"></script>
  <script src="inputName.js"></script>
  <script src="InputNameCtrl.js"></script>
  <script src="inputAge.js"></script>
  <script src="InputAgeCtrl.js"></script>

  <form name="myForm" class="form-horizontal" novalidate>
    <div class="form-group">
      <input-name ng-model='person.name' required></input-name>
    </div>

    <div class="form-group">
      <input-email ng-model='person.email' required></input-email>
    </div>

    <div class="form-group">
      <input-age ng-model='person.age' required></input-age>
    </div>

    <!-- Not using a directive -->
    <div class="form-group">
      <label class="col-sm-2 control-label">Country</label>
      <div class="col-sm-4" ng-class="{'has-error': myForm.country.$invalid}">
        <input type="text" name="country" ng-model="person.country" class="formInput form-control" required>
        <span ng-show="myForm.country.$error.required && myForm.country.$dirty" class="help-block">Can't be blank</span>
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-4">
        <button class="btn btn-primary" ng-disabled="myForm.$invalid">
          <span class="glyphicon glyphicon-cloud-upload"></span> Save
        </button>
      </div>
    </div>
  </form>

  Person: <pre>{{person | json}}</pre>

  Form $error: <pre>{{myForm.$error | json}}</pre>
  <p>Is the form valid?: {{myForm.$valid}}</p>

  <p>Is name valid?: {{myForm.name.$valid}}</p>
  <p>Is email valid?: {{myForm.email.$valid}}</p>
  <p>Is age valid?: {{myForm.age.$valid}}</p>
  <p>Is country valid?: {{myForm.country.$valid}}</p>
</body>
</html>
'use strict';

app.directive('inputEmail', function() {
  return {
    restrict: 'E',
    templateUrl: 'input-email.html',
    replace: false,
    controller: 'InputEmailCtrl',
    require: ['^form', 'ngModel'],

    // See Isolating the Scope of a Directive http://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive
    scope: {},

    link: function(scope, element, attrs, ctrls) {
      scope.form = ctrls[0];
      var ngModel = ctrls[1];

      if (attrs.required !== undefined) {
        // If attribute required exists
        // ng-required takes a boolean
        scope.required = true;
      }

      scope.$watch('email', function() {
        ngModel.$setViewValue(scope.email);
      });
    }
  };
});
<label class="col-sm-2 control-label">Email</label>
<div class="col-sm-4" ng-class="{'has-error': form.email.$invalid}">
  <input type="email" name="email" ng-model="email" class="form-control formInput" ng-required="required">

  <span ng-show="form.email.$error.required && form.email.$dirty" class="help-block">Can't be blank</span>
  <span ng-show="form.email.$error.email" class="help-block">Not a valid email</span>
</div>
'use strict';

app.controller('InputEmailCtrl', ['$scope', function($scope) {
}]);
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-4" ng-class="{'has-error': form.name.$invalid}">
  <input type="text" class="formInput form-control" name="name" ng-pattern="/^[a-zA-Z]+$/" ng-model="name"  ng-required="required">

  <span ng-show="form.name.$error.required && form.name.$dirty" class="help-block">Can't be blank</span>
  
  <span ng-show="form.name.$invalid && form.name.$dirty" class="help-block">Only letters are allowed</span>
</div>
'use strict';

app.directive('inputName', function() {
  return {
    restrict: 'E',
    templateUrl: 'input-name.html',
    replace: false,
    controller: 'InputNameCtrl',
    require: ['^form', 'ngModel'],

    // See Isolating the Scope of a Directive http://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive
    scope: {},

    link: function(scope, element, attrs, ctrls) {
      scope.form = ctrls[0];
      var ngModel = ctrls[1];

      if (attrs.required !== undefined) {
        // If attribute required exists
        // ng-required takes a boolean
        scope.required = true;
      }

      scope.$watch('name', function() {
        ngModel.$setViewValue(scope.name);
      });
    }
  };
});
'use strict';

app.controller('InputNameCtrl', ['$scope', function($scope) {
}]);
<label class="col-sm-2 control-label">Age</label>
<div class="col-sm-4" ng-class="{'has-error': form.age.$invalid}">
  <input type="text" name="age"
         min="0" max="150"
         ng-pattern="/^(0|[1-9][0-9]*)$/"
         ng-model="age"
         class="formInput form-control" ng-required="required">
         
 <span ng-show="form.age.$error.required && form.age.$dirty" class="help-block">Can't be blank</span>
  <span ng-show="form.age.$error.min && form.age.$dirty" class="help-block">Should be &ge; 0</span>
  <span ng-show="form.age.$error.max && form.age.$dirty" class="help-block">Should be &le; 150</span>
  <span ng-show="form.age.$error.pattern" class="help-block">Not a valid number !</span>
</div>
'use strict';

app.directive('inputAge', function() {
  return {
    restrict: 'E',
    templateUrl: 'input-age.html',
    replace: false,
    controller: 'InputAgeCtrl',
    require: ['^form', 'ngModel'],

    // See Isolating the Scope of a Directive http://docs.angularjs.org/guide/directive#isolating-the-scope-of-a-directive
    scope: {},

    link: function(scope, element, attrs, ctrls) {
      scope.form = ctrls[0];
      var ngModel = ctrls[1];

      if (attrs.required !== undefined) {
        // If attribute required exists
        // ng-required takes a boolean
        scope.required = true;
      }

      scope.$watch('age', function() {
        ngModel.$setViewValue(scope.age);
      });
    }
  };
});
'use strict';

app.controller('InputAgeCtrl', ['$scope', function($scope) {
}]);