Example for stackoverflow. Server side validation

by Stepan Kasyanenko

HTML

<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>

CSS

.error {
  color: red;
  font-style: italic;
}

JavaScript

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);
        });
      },
    };
  });