In AngularJS, asynchronous validation is useful when checking values that require a server request, such as:
Checking username availability in a database.
Validating email uniqueness.
Any validation requiring an API call.
1. Why Use Async Validation?
Prevents unnecessary form submissions if the username is already taken.
Provides instant feedback to users without waiting for submission.
Enhances user experience by validating data before submission.
2. How Async Validation Works in AngularJS?
AngularJS provides the $asyncValidators
object inside directives.
$asyncValidators
should return a promise ($q
or $http
).
If the promise resolves, validation passes.
If the promise rejects, validation fails.
3. Implementing Async Username Validation
Step 1: Define the Directive for Username Check
var app = angular.module('myApp', []);
app.directive('checkUsername', function($q, $timeout) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$asyncValidators.usernameTaken = function(value) {
var deferred = $q.defer();
// Simulating an API request with $timeout (Replace this with actual $http call)
$timeout(function() {
var takenUsernames = ['admin', 'testuser', 'john123']; // Example taken usernames
if (takenUsernames.includes(value)) {
deferred.reject(); // Username is taken (validation fails)
} else {
deferred.resolve(); // Username is available (validation passes)
}
}, 1000); // Simulate network delay of 1s
return deferred.promise;
};
}
};
});
Step 2: Use the Directive in the Form
<div ng-app="myApp" ng-controller="FormController">
<form name="userForm" novalidate>
<label>Username:</label>
<input type="text" name="username" ng-model="user.username" check-username required>
<p ng-show="userForm.username.$pending.usernameTaken">🔄 Checking availability...</p>
<p ng-show="userForm.username.$error.usernameTaken">❌ Username is already taken.</p>
<p ng-show="userForm.username.$valid && !userForm.username.$pending.usernameTaken">✅ Username is available.</p>
<button type="submit" ng-disabled="userForm.$invalid">Submit</button>
</form>
</div>
4. How It Works?
✔ User types a username in the input field.
✔ The directive triggers a simulated API call using $timeout
(replace with $http
for real APIs).
✔ If the username is taken, $asyncValidators.usernameTaken
rejects the promise.
✔ If the username is available, the promise resolves.
✔ Form shows appropriate messages based on the validation state.
✔ The submit button is disabled if the username is unavailable.
5. Using $http
for Real API Calls
In a real application, replace $timeout
with an $http
request:
Updated Directive with $http
app.directive('checkUsername', function($q, $http) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$asyncValidators.usernameTaken = function(value) {
var deferred = $q.defer();
// Simulate an API request to check username availability
$http.get('/api/check-username?username=' + value).then(
function(response) {
if (response.data.isTaken) {
deferred.reject(); // Username taken
} else {
deferred.resolve(); // Username available
}
},
function() {
deferred.reject(); // Error case (Assume username is taken)
}
);
return deferred.promise;
};
}
};
});
6. Example API Response for /api/check-username
If using a backend like Node.js, a simple Express.js route might look like this:
app.get('/api/check-username', function(req, res) {
const takenUsernames = ['admin', 'testuser', 'john123'];
const isTaken = takenUsernames.includes(req.query.username);
res.json({ isTaken: isTaken });
});
7. Summary of Async Validation
Feature | Description |
---|---|
Uses $asyncValidators | Handles async operations inside a directive. |
Returns a Promise | $q.defer() or $http must return a promise. |
Shows Pending State | ng-show="userForm.username.$pending.usernameTaken" shows a loading message. |
Validates Against Server Data | Example shows username availability check via API. |