0

I have created a async validator 'username-validator' to check username availability and to avoid number of remote calls I am updating ng-model on 'blur' event rather than on 'key press'. So validator is triggered only on 'blur' event.

<input type="text" ng-model="signup.username" name="username"
  required 
  username-validator 
  ng-model-options="{ updateOn: 'blur' }">

But when form gets submitted it checks if form is valid and only then it gets submitted.

$scope.submit = function(form) {
  if (form.$valid) {
    alert('submitting', $scope.signup.username, $scope.signup.password);
  }
};

But when I am clicking on Submit button and if form is in $pending state then form doesn't get submitted in one click, because at the time of click it is in $pending state and $valid is undefined.

I want to write my $scope.submit function to handle submission once $pending state is resolved.

How do i do it?

Don't want to disable the Submit button for $pending state.

To demonstrate the problem I am adding running snippet with it.

angular.module('app', ['ngMessages'])
  .controller('MainCtrl', function($scope) {
    $scope.signup = {};
    $scope.submit = function(form) {
      if (form.$valid) {

        alert('submitting ' +  $scope.signup.username + ' ' + $scope.signup.password);
      }

    };
  })
  .directive('usernameValidator', function($q, $timeout) {
    return {
      require: 'ngModel',
      link: function(scope, element, attrs, ngModel) {
        ngModel.$asyncValidators.username = function(modelValue, viewValue) {
          if (!viewValue) {
            return $q.when(true);
          }
          var deferred = $q.defer();
          $timeout(function() {
            // Faking actual server-side validity check with $http.
            // Let's pretend our service is so popular all short username are already taken
            if (viewValue && viewValue.length < 5) {
              deferred.reject();
            }

            deferred.resolve();
          }, 2000);
          return deferred.promise;
        };
      }
    };
  });
.validation-error {
  color: red;
}
.validation-pending {
  color: orange;
}
<!DOCTYPE html>
<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular-messages.min.js"></script>
  <script src="script.js"></script>

  <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body ng-app="app">
  <div ng-controller="MainCtrl">
    <form name="myForm" ng-submit="submit(myForm)" novalidate>
      <div>
        <label>
          Username:
          <input type="text" ng-model="signup.username" name="username" required username-validator ng-model-options="{ updateOn: 'blur' }">
        </label>
        <div ng-if="myForm.username.$dirty">
          <div ng-messages="myForm.username.$error" class="validation-error">
            <div ng-message="required">Username required</div>
            <div ng-message="username">Username already in use</div>
          </div>
          <div ng-messages="myForm.username.$pending" class="validation-pending">
            <div ng-message="username">Checking username availability...</div>
          </div>
        </div>
      </div>
      <div>
        <label>
          Password:
          <input type="password" ng-model="signup.password" name="password" required>
        </label>
        <div ng-messages="myForm.password.$error" ng-if="myForm.password.$dirty" class="validation-error">
          <div ng-message="required">Password required</div>
        </div>
      </div>
      <button type="submit">Submit</button>
    </form>
  </div>
</body>

</html>

1 Answer 1

0

You could attach the promise to the scope when checking for the username

scope.usernameCheck = deferred.promise;
return deferred.promise;

Then in your submit function wait for the promise to be resolved

$scope.submit = function(form) {
    if ($scope.usernameCheck) {
        $scope.usernameCheck.then(function() {
            if (form.$valid) {
                alert('submitting ' +  $scope.signup.username + ' ' + $scope.signup.password);
            }
        });
    }
};
Sign up to request clarification or add additional context in comments.

1 Comment

@Vibhanshu What was the error? I'm guessing the usenameCheck isn't getting tied to the correct scope.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.