简体   繁体   中英

How to asynchronously validate form in Angular after submit?

I have a registration form validating client-side that works fine. My app has also a server-side validation which returns the client a JSON with errors for each field.

I try to handle them like this:

// errors = { 
//    "username": [
//        "Account 'test2@test.com' already exist!"
//    ]
// };

for(var field in errors) {
  $scope.RegForm.$setValidity(field, false);
  $scope.RegForm[field].$error.server = errors[field].join('\n');
}

The problem is that errors remain visible even when I change field. I need to set validity back to true, and remove server error at some moment. Just not sure how and when.

How to properly treat server data in order to make them change? $asyncValidators will not work, because in the case of username field I'm not allowed to register user, just to see if such username is free.

Try like this

for (var field in errors) {
    $timeout(function(){
        $scope.RegForm.$setValidity(field, false);
        $scope.RegForm[field].$error.server = errors[field].join('\n');
    });
}

Based on the responses suggested in AngularJS - Server side validation and client side forms , we create a directive that will reset the validation after changing the properties of the model.

Live example on jsfiddle .

 angular.module('ExampleApp', ['ngMessages']) .controller('ExampleController', function($scope, ServerService) { $scope.user = {}; $scope.doSubmit = function(myForm) { ServerService.save().then(function(errors) { // Set error from server on our form angular.forEach(errors, function(error) { myForm[error.fieldName].$setValidity(error.error, false); }); }); }; }) //Simulate Ajax call .service('ServerService', function($q, $timeout) { var errorsFromServer = [{ fieldName: "firstName", error: "serverError" }, { fieldName: "lastName", error: "serverError" }, { fieldName: "email", error: "serverError" }, { fieldName: "email", error: "serverError2" }]; return { save: function() { return $q.when(errorsFromServer); } }; }) .directive('serverValidation', function() { return { restrict: "A", require: "ngModel", scope: { ngModel: "=", serverValidation: "=" // String or array of strings with name of errors }, link: function(scope, elem, attr, ngModelCtrl) { function setValidity(errorName) { console.log(errorName); ngModelCtrl.$setValidity(errorName, true); } if (typeof(scope.serverValidation) == "string") { console.log(scope.serverValidation); scope.arrServerValidation = [scope.serverValidation]; } else { scope.arrServerValidation = scope.serverValidation; } var firstError = scope.arrServerValidation[0]; scope.$watch('ngModel', function() { // workaround to don't update $setValidity, then changed value of ngModel // update $setValidity, only when server-error is true if (firstError && ngModelCtrl.$error[firstError]) angular.forEach(scope.arrServerValidation, setValidity); }); }, }; }); 
 .error { color: red; font-style: italic; } 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-messages.min.js"></script> <div ng-app="ExampleApp"> <div ng-controller="ExampleController"> <ng-form name="myForm"> <input ng-model="user.firstName" name="firstName" required server-validation="'serverError'"> <div ng-messages="myForm.firstName.$error" class="error"> <div ng-message="required">firstName is required</div> <div ng-message="serverError">firstName is server error</div> </div> <input ng-model="user.lastName" name="lastName" required server-validation="'serverError'"> <div ng-messages="myForm.lastName.$error" class="error"> <div ng-message="required">lastName is required</div> <div ng-message="serverError">lastName is server error</div> </div> <input ng-model="user.email" name="email" required server-validation="['serverError','serverError2']"> <div ng-messages="myForm.email.$error" class="error" multiple="true"> <div ng-message="required">email is required</div> <div ng-message="serverError">email is server error</div> <div ng-message="serverError2">email is server error 2</div> </div> <input ng-disabled="myForm.$invalid" ng-click="doSubmit(myForm)" type="submit"> </ng-form> </div> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM