angularjs: custom directive to check if a username exists

20,325

there is a great tutorial by yearofmoo about $asyncvalidators in angular1.3. it allows you to easily show pending status when the field is being checked by the backend:

here's a working plnkr

app.directive('usernameAvailable', function($timeout, $q) {
  return {
    restrict: 'AE',
    require: 'ngModel',
    link: function(scope, elm, attr, model) { 
      model.$asyncValidators.usernameExists = function() {

        //here you should access the backend, to check if username exists
        //and return a promise
        //here we're using $q and $timeout to mimic a backend call 
        //that will resolve after 1 sec

        var defer = $q.defer();
        $timeout(function(){
          model.$setValidity('usernameExists', false); 
          defer.resolve;
        }, 1000);
        return defer.promise;
      };
    }
  } 
});

html:

<form name="myForm">
  <input type="text" 
        name="username"
        ng-model="username" 
        username-available 
        required
        ng-model-options="{ updateOn: 'blur' }">
  <div ng-if="myForm.$pending.usernameExists">checking....</div>
  <div ng-if="myForm.$error.usernameExists">username exists already</div>
</form>

note the use of ng-model-options, another cool feature of 1.3


edit

here's a plnkr that shows how to use $http in the directive. note that it is only requesting another .json file, that contains a true/false value. and the directive will set validity on the ng-model accordingly.

Share:
20,325
Lee Lee
Author by

Lee Lee

Updated on July 09, 2022

Comments

  • Lee Lee
    Lee Lee almost 2 years

    I have my registration form with textbox username. I want to do is when the user enter the username, the custom directive will check if the entered username is exists in the database.

    directives.js

    angular.module('installApp').directive('pwCheck', function ($http) {
      return {
        require: 'ngModel',
          link: function (scope, elem, attrs, ctrl) {
            elem.on('blur', function (evt) {
              scope.$apply(function () {
              $http({ 
              method: 'GET', 
              url: '../api/v1/users', 
              data: { 
                username:elem.val(), 
                dbField:attrs.ngUnique 
              } 
          }).success(function(data, status, headers, config) {
            ctrl.$setValidity('unique', data.status);
            });
           });
          });
         }
        }
    });
    

    If it's exists, my div class = "invalid" will shown in the html form with label "Username already exists."

    registration.html

        <form name  = "signupform">
          <label>{{label.username}}</label>
            <input type="text" id = "username" name = "username" ng-model="user.username" class="form-control"></input>
            <div class="invalid" ng-show="signupform.username.$dirty && signupform.username.$invalid"><span ng-show="signupform.username.$error.unique">Username already exists.</span>
            </div>
        </form>
    

    But right now, they are not working :-(,am I doing right? Please advice or suggest me things I should do. Thanks in advance.

  • Lee Lee
    Lee Lee over 9 years
    That is great @Nitsan Baleli. I am new to directives may I ask you another question, can you help me how to access my backend? I tried the plunker and no matter what I enter it always said that the user is already exists. I know I need to add some code but I do not know how to access my backend via directives and compare them. Thanks a lot in advance
  • Lee Lee
    Lee Lee over 9 years
    hi there. I saw the updated answer and fork it :-). I put some values inside the backend.json. I entered them one by one and it's okay its display "user already exists" but when I enter a value which is not listed in the .json it still displays "user already exists", am I missing something? Thank you again, Here is the link plnkr.co/edit/2kIjx46buEinjpWx9rpR?p=preview
  • Nitsan Baleli
    Nitsan Baleli over 9 years
    @Yaoming keep in mind that setting the model as valid/invalid is made with this command: model.$setValidity('usernameExists', res.data); so what ever the backend gives you, you need to decide and set the appropriate true/false value on the model.
  • Lee Lee
    Lee Lee over 9 years
    Hello is this correct ` return $http.get('../api/v1/users').then(function(res)`?
  • Lee Lee
    Lee Lee over 9 years
    Okay let's chat. . Where do you want?
  • Lee Lee
    Lee Lee over 9 years
    Sorry if I am too much. . But I need your help, what should I do to access my backend?
  • Nitsan Baleli
    Nitsan Baleli over 9 years
  • Lee Lee
    Lee Lee over 9 years
    Thank you Nitsan Baleli. Your code now is working in my project, I just changed some process but it works fine. Thank you a lot. :-)
  • Eka Rudianto
    Eka Rudianto almost 9 years
    Hi @NitsanBaleli I've tried your method, but it seems the ngModel value didn't get updated, did I missed something ?
  • Nitsan Baleli
    Nitsan Baleli almost 9 years
    @user3860691 try this approach plnkr.co/edit/QrI9Y9W72ejCKZXq1I3v?p=preview
  • Eon
    Eon almost 8 years
    bit late - due to bug github.com/angular/angular.js/issues/10035 you might want to set $q.defer(); to a variable, and manually have $q.resolve() fired when the validation passes - otherwise it still destroys a value within your scope.