# Angular directive for unique username

I looked at a bunch of AngularJS directives checking for uniqueness of a username and decided to try for the simplest implementation. It does what I want but may not really be 'idiomatic' Angular.

Here is the form element:

<input type="text"
required
/>
<span class="hide-while-in-focus" ng-show="thisform.username.$error.unique">Username taken!</span> Here's the directive: .directive('uniqueUsername', function($http) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
element.bind('blur', function (e) {
ngModel.$setValidity('unique', true);$http.get("/api/checkUnique/" + element.val()).success(function(data) {
if (data) {
ngModel.$setValidity('unique', false); } }); }); } }; }) And the ExpressJS call: if (data) { console.log("found " + data.username); return res.send(data.username); } else { console.log("not found"); return res.send(404); } I would appreciate any feedback on why this is good or bad and if possible a revision that uses$scope.watch on the model.

• I would avoid naming thisform..., too easy to confuse with this.form... Aug 3 '14 at 5:10

## Service

Using a service is another large advantage. Currently, the directive requires $http and thus becomes bound to the api. Using a service, one can create a mock service to test the directive independently of the api. Another advantage is that the logic for the uniqueness test is now isolated from the view. This code can then be reused in a controller, another directive, or even another service. function UserService($q, $http) { this.isUnique = function(username) { if (notEmpty(username)) { var uri = '/api/checkUnique/' + username; return$http.get(uri);
}
return $q.reject("Invalid User name"); } } ## Directive userService is must now be injected into the directive instead of$http . Since the uniqueness test is done when the model changes, one can also create a watch on the model rather than binding it to an event.

In the future, you can use the controller.$parsers.unshift command instead of a scope.$watch. Unfortunately, $parsers doesn't allow for responses from a$promise. See issue #6416.

return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
scope.$watch(attrs.ngModel, function(value) { userService.isUnique(value) .then(function(data) { ngModel.$setValidity('unique', notEmpty(data));
})
.catch(function() {