<!DOCTYPE html>
<html>

  <head>
    <script data-require="jquery@2.0.3" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" data-semver="3.3.2" data-require="bootstrap@3.3.2" />
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js" data-semver="3.3.2" data-require="bootstrap@3.3.2"></script>
    <script data-require="angular.js@1.4.0-rc.0" data-semver="1.4.0-rc.0" src="https://code.angularjs.org/1.4.0-rc.0/angular.js"></script>
    <script src="https://rawgit.com/pocesar/angular-async-validator/master/angular-async-validator.js"></script>
    <link href="style.css" rel="stylesheet" />
  </head>

  <body class="container" ng-controller="Main as main">
    <tabs class="col-xs-12">
        <tab label="'Simple'">
          <div ng-include="'simple.html'"></div>
        </tab>
        <tab label="'Advanced'">
          <div ng-include="'advanced.html'"></div>
        </tab>
        <tab label="'Promises'">
          <div ng-include="'promises.html'"></div>
        </tab>
        <tab label="'Multiple'">
          <div ng-include="'multiple.html'"></div>
        </tab>
    </tabs>
    <script src="script.js"></script>
  </body>

</html>
// Code goes here

angular
.module('app', ['AsyncValidator'])
.config(['AsyncValidatorProvider', function(AsyncValidatorProvider){
    
    AsyncValidatorProvider
    .register('registeredValidator', [function(){
        return function(value, options, $model){
            return angular.isUndefined($model.$viewValue) || $model.$viewValue.length < 5;
        }
    }])
    
    .register('asyncHttp', ['$http', function($http){
        return function(value, options, $model){
            return $http.get('test.json').then(function(result){
                return result.error;
            });
        };
    }])
    
    .register('setOtherValidities', [function(){
        return function(value, options, $model) {
           if ($model.$viewValue) {
                if ($model.$viewValue.length < 4) {
                    $model.$setValidity(options.key, false);  
                    return false;
                } 
           }
           $model.$setValidity(options.key, true);  
           return !$model.$error[options.key];
        };
    }])
    
    .register('reuseValidator', [function(){
        return function(value, options, $model) {
            switch (options.mode) {
                case 'number':
                    return /^[0-9]+$/.test($model.$viewValue);
                case 'object':
                    try {
                        return angular.isObject(JSON.parse($model.$viewValue));
                    } catch (e) {
                        return false;
                    }
                case 'boolean':
                    return !!$model.$viewValue;
            }
            return true; // never fail the base validator
        };
    }])
    ;
    
}])
.controller('Main', ['$q', '$timeout', function($q, $timeout){
    this.data = {
        
    };
    
    this.loaded = false;
    
    this.controllerValidator = function(model, options){
        
    };
}])
.directive('tabs', [function(){
    return {
        restrict: 'E',
        controllerAs: 'tabs',
        templateUrl: 'tabset.html',
        transclude: true,
        controller: [function(){
            var current = null;
            this.labels = [];
            this.current = function(id){
                if (id) {
                    current = id;
                }
                return current;
            };
            this.label = function(label){
                this.labels.push(label);
            };
        }]
    };
}])
.directive('tab', [function(){
    return {
        restrict: 'E',
        require: '^tabs',
        transclude: true,
        templateUrl: 'tab.html',
        scope: {
            label: '='
        },
        link: function(scope, el, attrs, ctrl){
            ctrl.label(scope.label);
            scope.current = function(){
               return scope.label == ctrl.current();  
            };
        }
    };
}]);

angular.bootstrap(document, ['app'], {strictDi: true});
/* Styles go here */

.nav-tabs {
    margin-bottom: 20px;
}

.ng-pending + .loading:after {
    content: "Loading ...";
}

.ng-invalid.ng-touched {
    box-shadow: 0px 0px 3px red;
}
<div ng-if="current()">
    <div class="tab-pane active">
        <div class="panel panel-default">
            <div class="panel-heading" role="tabpanel">{{ label }}</div>
            <div class="panel-body" ng-transclude></div>
        </div>
    </div>
</div>
<div class="row">
  <div class="col-xs-12">
    <ul class="nav nav-tabs" role="tablist">
      <li ng-repeat="label in tabs.labels"  ng-class="{'active': tabs.current() == label}">
          <a href="#" ng-click="tabs.current(label)">{{ label }}</a>
      </li>
    </ul>
    <div ng-transclude class="tab-content"></div>
  </div>
</div>
<form name="main.simpleForm">
    <div class="form-group">
        <label>async-validator="'$value.length > 0'"</label>
        <input type="text" class="form-control" async-validator="'$value.length > 0'" name="simple1" ng-model="main.data.simple1"> 
        {{ main.simpleForm.simple1.$error }}
    </div>
    <div class="form-group">
        <label>async-validator="'main.loaded || $value'"</label>
        <input type="text" class="form-control" async-validator="'main.loaded || $value'" name="simple2" ng-model="main.data.simple2"> 
        {{ main.simpleForm.simple2.$error }} {{ {'main.loaded': main.loaded } }} <button type="button" class="btn" ng-click="main.loaded=!main.loaded;main.simpleForm.simple2.$validate();">Toggle 'main.loaded'</button>
    </div>
    <div class="form-group">
        <label>async-validator="'$value != main.data.simple2'"></label>
        <input type="text" class="form-control" async-validator="'$value != main.data.simple2'" name="simple3" ng-model="main.data.simple3"> 
        {{ main.simpleForm.simple3.$error }}
    </div>
</form>
<form name="main.advancedForm">
    <div class="form-group">
        <label>async-validator="['registeredValidator','$value.length > 3']"</label>
        <input type="text" async-validator="['registeredValidator','$value.length > 3']" class="form-control" name="advanced1" ng-model="main.data.advanced1"> 
        {{ main.advancedForm.advanced1.$error }}
    </div>
    
    <div class="form-group">
        <label>async-validator="{number: 'reuseValidator', object: 'reuseValidator', boolean: 'reuseValidator'}"</label>
        <input type="text" 
            async-validator="{number: 'reuseValidator', object: 'reuseValidator', boolean: 'reuseValidator'}"
            async-validator-options-number="{mode:'number'}"
            async-validator-options-object="{mode:'object'}"
            async-validator-options-boolean="{mode:'boolean'}"
            class="form-control" name="advanced2" 
            ng-model="main.data.advanced2"> 
        {{ main.advancedForm.advanced2.$error }}
    </div>
</form>
<form name="main.multipleForm">
    <div class="form-group">
        <label>async-validator="'setOtherValidities'" async-validator-options="{ key: 'anotherValidation' }"</label>
        <input type="text" name="multiple1" class="form-control" async-validator="'setOtherValidities'" async-validator-options="{ key: 'anotherValidation' }" ng-model="main.data.multiple1">
        {{ main.multipleForm.multiple1.$error }}
    </div>
</form>
<form name="main.promisesForm">
    <div class="form-group">
        <label>async-validator="'asyncHttp'"</label>
        <input type="text" async-validator="'asyncHttp'" name="promises1" class="form-control" ng-model="main.data.promises1"> <i class="loading"></i>
        <br>{{ main.promisesForm.promises1.$error }}
    </div>
</form>
{
    "error": true
}