Handling async validation (e.g., checking username availability)

Loading

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

FeatureDescription
Uses $asyncValidatorsHandles async operations inside a directive.
Returns a Promise$q.defer() or $http must return a promise.
Shows Pending Stateng-show="userForm.username.$pending.usernameTaken" shows a loading message.
Validates Against Server DataExample shows username availability check via API.

Leave a Reply

Your email address will not be published. Required fields are marked *