show validation error messages on submit in angularjs show validation error messages on submit in angularjs angularjs angularjs

show validation error messages on submit in angularjs


I found this fiddle http://jsfiddle.net/thomporter/ANxmv/2/ which does a nifty trick to cause control validation.

Basically it declares a scope member submitted and sets it true when you click submit. The model error binding use this extra expression to show the error message like

submitted && form.email.$error.required

UPDATE

As pointed out in @Hafez's comment (give him some upvotes!), the Angular 1.3+ solution is simply:

form.$submitted && form.email.$error.required


Since I'm using Bootstrap 3, I use a directive:(see plunkr)

    var ValidSubmit = ['$parse', function ($parse) {        return {            compile: function compile(tElement, tAttrs, transclude) {                return {                    post: function postLink(scope, element, iAttrs, controller) {                        var form = element.controller('form');                        form.$submitted = false;                        var fn = $parse(iAttrs.validSubmit);                        element.on('submit', function(event) {                            scope.$apply(function() {                                element.addClass('ng-submitted');                                form.$submitted = true;                                if(form.$valid) {                                    fn(scope, {$event:event});                                }                            });                        });                        scope.$watch(function() { return form.$valid}, function(isValid) {                            if(form.$submitted == false) return;                            if(isValid) {                                element.removeClass('has-error').addClass('has-success');                            } else {                                element.removeClass('has-success');                                element.addClass('has-error');                            }                        });                    }                }            }        }    }]    app.directive('validSubmit', ValidSubmit);

and then in my HTML:

<form class="form-horizontal" role="form" name="form" novalidate valid-submit="connect()">  <div class="form-group">    <div class="input-group col col-sm-11 col-sm-offset-1">      <span class="input-group-addon input-large"><i class="glyphicon glyphicon-envelope"></i></span>      <input class="input-large form-control" type="email" id="email" placeholder="Email" name="email" ng-model="email" required="required">    </div>    <p class="col-sm-offset-3 help-block error" ng-show="form.$submitted && form.email.$error.required">please enter your email</p>    <p class="col-sm-offset-3 help-block error" ng-show="form.$submitted && form.email.$error.email">please enter a valid email</p>  </div></form>

UPDATED

In my latest project, I use Ionic so I have the following, which automatically puts .valid or .invalid on the input-item's:

.directive('input', ['$timeout', function ($timeout) {  function findParent(element, selector) {    selector = selector || 'item';    var parent = element.parent();    while (parent && parent.length) {      parent = angular.element(parent);      if (parent.hasClass(selector)) {        break;      }      parent = parent && parent.parent && parent.parent();    }    return parent;  }  return {    restrict: 'E',    require: ['?^ngModel', '^form'],    priority: 1,    link: function (scope, element, attrs, ctrls) {      var ngModelCtrl = ctrls[0];      var form = ctrls[1];      if (!ngModelCtrl || form.$name !== 'form' || attrs.type === 'radio' || attrs.type === 'checkbox') {        return;      }      function setValidClass() {        var parent = findParent(element);        if (parent && parent.toggleClass) {          parent.addClass('validated');          parent.toggleClass('valid', ngModelCtrl.$valid && (ngModelCtrl.$dirty || form.$submitted));          parent.toggleClass('invalid', ngModelCtrl.$invalid && (ngModelCtrl.$dirty || form.$submitted));          $timeout(angular.noop);        }      }      scope.$watch(function () {        return form.$submitted;      }, function (b, a) {        setValidClass();      });      var before = void 0;      var update = function () {        before = element.val().trim();        ngModelCtrl.$setViewValue(before);        ngModelCtrl.$render();        setValidClass();      };      element        .on('focus', function (e) {          if (ngModelCtrl.$pristine) {            element.removeClass('$blurred');          }        })        .on('blur', function (e) {          if (ngModelCtrl.$dirty) {            setValidClass();            element.addClass('$blurred');          }        }).on('change', function (e) {          if (form.$submitted || element.hasClass('$blurred')) {            setValidClass();          }        }).on('paste', function (e) {          if (form.$submitted || element.hasClass('$blurred')) {            setValidClass();          }        })      ;    }  };}])

and then in the HTML:

    <form name='form' novalidate="novalidate" ng-submit="auth.signin(form, vm)">          <label class="item item-input item-floating-label">            <span class="input-label">Email</span>            <input type="email" placeholder="Email" ng-model="vm.email" autofocus="true" required              >          </label>          <button ng-if="!posting" type="submit" class="item button-block item-balanced item-icon-right  call-to-action">Login<i class="icon ion-chevron-right"></i>          </button>

and in the controller:

  self.signin = function (form, data) {    if (!form.$valid) return;    Authentication.emailLogin(data)    //...

so, now, in the CSS, you can do stuff like:

.item.valid::before{    float: right;    font-family: "Ionicons";    font-style: normal;    font-weight: normal;    font-variant: normal;    text-transform: none;    text-rendering: auto;    line-height: 1;    -webkit-font-smoothing: antialiased;    -moz-osx-font-smoothing: grayscale;    color: #66cc33;    margin-right: 8px;    font-size: 24px;    content: "\f122";}.item.invalid::before{    float: right;    font-family: "Ionicons";    font-style: normal;    font-weight: normal;    font-variant: normal;    text-transform: none;    text-rendering: auto;    line-height: 1;    -webkit-font-smoothing: antialiased;    -moz-osx-font-smoothing: grayscale;    color: #ef4e3a;    margin-right: 8px;    font-size: 24px;    content: "\f12a";/*    border-left: solid 2px #ef4e3a !important;    border-right: solid 2px #ef4e3a !important;*/}

MUCH SIMPLER!


I also had the same issue, I solved the problem by adding a ng-submit which sets the variable submitted to true.

<form name="form" ng-submit="submitted = true" novalidate><div>    <span ng-if="submitted && form.email.$error.email">invalid email address</span>     <span ng-if="submitted && form.email.$error.required">required</span>    <label>email</label>    <input type="email" name="email" ng-model="user.email" required></div><div>    <span ng-if="submitted && form.name.$error.required">required</span>    <label>name</label>    <input type="text" name="name" ng-model="user.name" required></div><button ng-click="form.$valid && save(user)">Save</button></form>

I like the idea of using $submitted, I think I've to upgrade Angular to 1.3 ;)