Skip to content
This repository has been archived by the owner on Jul 1, 2020. It is now read-only.

Remote Validation (AJAX)

Ghislain B edited this page Mar 23, 2017 · 45 revisions

Implemented in version 1.3.25 but was improved in version 1.4.14

For a Remote Validation to work, it is expected that a declared function in your Controller will return a Promise in all cases. There is 2 ways of resolving a result, but the 2nd option is preferable, see them both below.

Backend Example
// define a function in your Controller which return a Promise
$scope.customRemoteValidationCheck = function() {
    var deferred = $q.defer();

    // probably use $http or any other AJAX service to talk to your server
    /*
    $http.get('/someUrl').success(function(data) {
        deferred.resolve({ isValid: data.isValid, message: data.message });
    });
    */

    // For example purposes
    // we simulate a server delay by using a simple setTimeout
    setTimeout(function() {
      // for simple test, let's just make sure user typed "abc"
      var isValid = ($scope.input1 === "abc") ? true : false;

      // Option #1, return a boolean for isValid
      deferred.resolve(isValid);

      // Option #2, or you can return an object as { isValid: bool, message: 'msg' }
      // this is to my opinion the best option to use
      deferred.resolve({ isValid: isValid, message: 'Returned error from promise.'});
    }, 1000);

    return deferred.promise;
}

Then calling it inside the DOM with the Directive would be as easy as declaring another Validator inside your validation declaration (see below). For the error message display, it's preferable to deal with it directly inside your defined function (as we just saw on top) and resolve the promise with an object that will include your error message, for example: deferred.resolve({ isValid: false, message: 'Server error message.'}); You could also use the alternate text but I would suggest not to and instead use the error message in the resolve. Please note that resolving the error message from the server will only show after the promise is finished (or should we say resolved), while on the other hand if you decide to use the alt=, this message would instead show right away (without waiting for server response) and is most probably not what you want (hence why I said, it's not a good suggestion).

Note

Please note that the function could be called with or without the parentheses (). Meaning this validation="custom:myFunction" is equal to this `validation="custom:myFunction()"

Directive

<!-- defining the remote function call by using `remote:` -->
<input type="text" class="form-control" name="input1" ng-model="input1" 
    validation="remote:customRemoteValidationCheck|required" />

<!-- or if you use the ControllerAs alias -->
<input type="text" class="form-control" name="input1" ng-model="input1" 
    validation="remote:vm.customRemoteValidationCheck|required" />

<!-- using alternate text but is probably not suggested -->
<input type="text" class="form-control" name="input1" ng-model="input1" 
    validation="remote:customRemoteValidationCheck:alt=Remote error|required" />

<!-- You can combine that with other validators as well -->
<input type="text" class="form-control" name="input1" ng-model="input1" 
    validation="alpha|min_len:2|remote:customRemoteValidationCheck|required" />

<!-- we could also pass argument(s) to the function -->
<input type="text" class="form-control" name="input1" ng-model="input1" 
    validation="remote:customRemoteValidationCheck($index)|required" />

Service

Same thing but your validator rules are defined in the controller

// inject the ValidationService inside your Controller
myApp.controller('Ctrl', function ($scope, ValidationService) {
  // start by creating the service
  var vs = new ValidationService();

  vs.addValidator({
    elmName: 'input1',
    scope: $scope,
    rules: 'remote:customRemoteValidationCheck|required'
  });

  // or if you use the Controller As alias
  // rules: 'remote:vm.customRemoteValidationCheck|required'

  // or combine it with multiple validators
  vs.addValidator({
    elmName: 'input1',
    scope: $scope,
    rules: 'alpha|min_len:2|remote:customRemoteValidationCheck|required'
  });

  // or as a 1 line
  vs.addValidator('input1', 'alpha|min_len:2|remote:customRemoteValidationCheck|required');
  });
});

Loading... Advise user while processing...

It's up to your taste on what to use but I would personally use the error message returned from the server and at same time use the ng-if ... form1.input1.$processing to advise the user that something is happening and is taking some time to process. You could also add a loading logo or text while doing this process, the nomenclature is: yourFormName.yourElementName.$processing

<input type="text" class="form-control" name="input1" ng-model="input1" 
    validation="remote:customRemoteValidationCheck|required" />
<div ng-if="form1.input1.$processing">
     Validating from Server....
</div>

or add a Bootstrap progress bar

<input type="text" class="form-control" name="input1" ng-model="input1" 
    validation="remote:customRemoteValidationCheck|required" />
<div ng-if="form1.input1.$processing" class="progress">
    <div class="progress-bar progress-bar-striped active" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 100%">
    </div>
</div>

or even better, make a CSS3 animation as shown on this StackOverflow answer. You can check the Live Demo on Plunker, which is showing just that, don't forget to update your CSS.

Clone this wiki locally