var app = angular.module('plunker', ['ngMockE2E']);
app.controller('MainCtrl', function($scope) {
$scope.model = {
firstname: 'Bob',
lastname: 'Barker'
};
});
app.run(function($httpBackend) {
$httpBackend.whenPOST('api/contact').respond(function(method, url, data) {
var errors = [];
data = JSON.parse(data);
if (data.firstname === "") errors.push('First name was not supplied.');
if (data.lastname === "") errors.push('Last name was not supplied.');
if (data.firstname === "Jon") return [500, ["You can't use that name."]];
return [200, errors];
});
});
app.directive('contactValidator', function($q, $http) {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$asyncValidators.contact = function(model) {
var defer = $q.defer();
if (model != null) {
//$errors is a custom property I made up to attach to the form name.
scope.contact.$errors = [];
$http.post('api/contact', model).success(function(errorList) {
if (errorList.length > 0) {
scope.contact.$errors = errorList;
defer.reject();
} else {
defer.resolve();
}
}).error(function(response) {
scope.contact.$errors.push('There was a general exception. ' + response);
defer.reject();
});
} else {
//Assume validated if model is empty;
defer.resolve();
}
return defer.promise;
}
//Setup a deep check on the entire model.
scope.$watch(attrs.ngModel, function(model) {
if (model != null) {
ngModel.$validate();
}
}, true);
}
}
});
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<link data-require="bootstrap@3.2.0" data-semver="3.2.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.css" />
<script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script data-require="bootstrap@3.2.0" data-semver="3.2.0" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.js"></script>
<script data-require="angular.js@*" data-semver="1.4.0-beta.0" src="https://code.angularjs.org/1.4.0-beta.0/angular.js"></script>
<script src="https://code.angularjs.org/1.4.0-beta.0/angular-mocks.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl" class="container">
<h1>Form Validation</h1>
<ng-form name="contact" ng-model-options="{allowInvalid: true}" ng-model="model" contact-validator>
<div class="row">
<div class="col-md-12">
<ng-messages for="contact.$invalid" ng-if="contact.$invalid">
<div class="alert alert-danger">
<ng-message when="contact">
<div ng-repeat="error in contact.$errors">{{error}}</div>
</ng-message>
</div>
</ng-messages>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label>First Name</label>
<input type="text" class="form-control" ng-model-options="{updateOn:'blur'}" ng-model="model.firstname" />
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" class="form-control" ng-model="model.lastname" />
</div>
<button class="btn btn-success" ng-disabled="contact.$invalid">Update</button>
</div>
</div>
</ng-form>
</body>
</html>