【问题标题】:show validation error messages on submit in angularjs在 angularjs 中提交时显示验证错误消息
【发布时间】:2013-09-14 04:44:15
【问题描述】:

我有一个表单,如果点击提交,它需要显示验证错误消息。

这是一个有效的plunker

 <form name="frmRegister" ng-submit="register();" novalidate>
      <div>
        <input placeholder="First Name" name="first_name" type="text" ng-model="user.firstName" required />
        <span ng-show="frmRegister.first_name.$dirty && frmRegister.first_name.$error.required">First Name is required</span>
      </div>
      <div>
        <input placeholder="Last Name" name="last_name" type="text" ng-model="user.lastName" required />
        <span ng-show="frmRegister.last_name.$dirty && frmRegister.last_name.$error.required">Last Name is required</span>
      </div>
      <div>
        <input placeholder="Email" name="email" type="email" ng-model="user.email" required />
        <span ng-show="frmRegister.email.$dirty && frmRegister.email.$error.required">Email is required.</span>
        <span ng-show="frmRegister.email.$dirty && frmRegister.email.$error.email">Invalid Email address.</span>
      </div>
      <input type="submit" value="Save" />
      <span ng-show="registered">YOU ARE NOW REGISTERED USER</span>
 </form>

当用户开始进行更改时,验证正常工作。但它不显示任何错误消息如果单击提交而不输入任何内容。

有没有想过实现这一目标?或者以其他方式如何在单击提交按钮时使每个输入字段 $dirty

【问题讨论】:

标签: javascript validation angularjs


【解决方案1】:

我发现了这个小提琴http://jsfiddle.net/thomporter/ANxmv/2/,它做了一个漂亮的技巧来导致控制验证。

基本上它声明了一个范围成员submitted,并在您单击提交时将其设置为真。模型错误绑定使用这个额外的表达式来显示错误消息,如

submitted && form.email.$error.required

更新

正如@Hafez's comment 中指出的(给他点赞!),Angular 1.3+ solution 很简单:

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

【讨论】:

  • 根据文档docs.angularjs.org/guide/…使用form.$submitted
  • 是的,这个解决方案并不虔诚,发布 Angular 1.3。现在有一个 $submitted 属性。
  • @Chandermani 只是想说,请在您的工作插件中包含 novalidate。 :)
  • @Chandermani:你能帮我处理这个链接吗? stackoverflow.com/questions/29557554/…
  • 该解决方案有效,但我认为对于正常的用例,它不能满足要求,form.email.$touched && form.email.$error 也应该显示错误。需要,所以实现结果的最佳方法是将验证留给控制器方法,检查表单验证,然后为每个属性调用 $setTouched。
【解决方案2】:

由于我使用的是 Bootstrap 3,因此我使用了一个指令: (见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);

然后在我的 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>

更新

在我的最新项目中,我使用 Ionic,所以我有以下内容,它会自动将 .valid.invalid 放在 input-item 上:

.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();
          }
        })
      ;

    }
  };
}])

然后在 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>

在控制器中:

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

    Authentication.emailLogin(data)
    //...

所以,现在,在 CSS 中,您可以执行以下操作:

.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;
*/
}

简单多了!

【讨论】:

  • 非常好!我对其进行了一些改进,并在 jsfiddl 中提供了带有 Bootstrap 3 风格的示例
  • 稍微修改为 require 表单控制器。现在您只能在 &lt;form&gt; 上组合 validSubmit 指令,并且您不必再手动从作用域中获取控制器。 updated jsfiddle.
  • 还有一个更新,现在包括对第一个输入(和一些 cmets)的自动对焦:new jsfiddle
  • 不妨在这里放一个最终版本:final jsfiddle.
  • @Plantface 我将您的指令与另一个指令组合在一起,该指令循环遍历所有表单组 div 并监视输入,以便它可以在验证状态更改时设置它们的 has-error 类。 gist.github.com/anonymous/97efc4f2f12ba51c5cf3
【解决方案3】:

我也遇到了同样的问题,我通过添加一个 ng-submit 将提交的变量设置为 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>

我喜欢使用 $submitted 的想法,我想我必须将 Angular 升级到 1.3 ;)

【讨论】:

    【解决方案4】:

    我可以想出两种方法来实现它。

    第一个是去掉novalidate,开启浏览器的验证。

    其次,可以像这样在表单无效时禁用save按钮

    <input ng-disabled="!frmRegister.$valid" type="submit" value="Save" />
    

    希望对你有帮助。

    【讨论】:

    • 谢谢,删除 novalidate 会给 safari ios 浏览器带来麻烦。它不提供验证弹出窗口。如果最初禁用提交按钮,我(用户)也感觉有点模棱两可。但这是处理它的好方法。
    【解决方案5】:

    有两种简单而优雅的方法。

    纯 CSS:

    在第一次提交表单后,尽管表单有效,Angular 会为刚刚提交的表单内的所有表单元素添加一个ng-submitted 类。

    我们可以使用.ng-submitted 通过 CSS 来控制我们的元素。

    如果您只想在用户提交时显示错误文本,例如

    .error { display: none }
    .ng-submitted .error {
         display: block;
    }
    

    使用 Scope 中的值:
    在第一次提交表单后,尽管表单有效,Angular 仍会将 [your form name].$submitted 设置为 true。因此,我们可以使用该值来控制元素。

    <div ng-show="yourFormName.$submitted">error message</div>
    <form name="yourFormName"></form>
    

    【讨论】:

    • 是的,你现在可以在 1.3+ 中执行此操作,但是当 OP 询问 1.3 尚未正式发布时:P
    【解决方案6】:

    我的 bootstrap 3 解决方案

    http://jsfiddle.net/rimian/epxrbzn9/

    <form class="form" name="form" ng-app novalidate>
      <div class="form-group">
        <input name="first_name"
              type="text"
              class="form-control"
              ng-model="first_name"
              placeholder="First Name"
              required />
      </div>
      <div class="form-group">
        <input name="last_name"
              type="text"
              class="form-control"
              ng-model="last_name"
              placeholder="Last Name"
              required />
      </div>
    
      <button
        type="submit"
        class="btn btn-primary btn-large"
        ng-click="submitted=true">
          Submit
      </button>
    
    <div ng-show="submitted && form.$invalid" class="alert alert-danger">
      <div ng-show="form.first_name.$error.required">
        First Name is Required
      </div>
      <div ng-show="form.last_name.$error.required">
        Last Name is Required
      </div>
    </div>
    
    </form>
    

    【讨论】:

    • 对 jsfiddle ng-show="(submitted && form.last_name.$invalid) || (!form.last_name.$pristine && form.last_name.$invalid)" 的更改将允许您to: 1. 表单加载时隐藏验证,2. 提交表单时显示所有损坏的验证,3. 当字段被触摸时显示验证消息。
    • @chrisghardwick 可以用你的建议更新小提琴吗?
    【解决方案7】:

    您只需要在提交之前检查表单是否脏且有效。查看以下代码。

    <form name="frmRegister" data-ng-submit="frmRegister.$valid && frmRegister.$dirty ? register() : return false;" novalidate>      
    

    您还可以通过以下更改禁用提交按钮:

    <input type="submit" value="Save" data-ng-disable="frmRegister.$invalid || !frmRegister.$dirty" />
    

    这应该有助于你的初始

    【讨论】:

    • 你也可以使用 frmRegister.$pristine 代替 !frmRegister.$dirty
    【解决方案8】:

    http://jsfiddle.net/LRD5x/30/ 一个简单的解决方案。

    HTML

    <form ng-submit="sendForm($event)" ng-class={submitted:submitted}>
    

    JS

    $scope.sendForm = function($event) {
      $event.preventDefault()
      $scope.submitted = true
    };
    

    CSS

    .submitted input.ng-invalid:not(:focus) {
        background-color: #FA787E;
    }
    
    input.ng-invalid ~ .alert{
        display:none;
    }
    .submitted input.ng-invalid ~ .alert{
        display:block;
    }
    

    【讨论】:

      【解决方案9】:

      我最喜欢realcrowd 的解决方案。

      HTML:

      <form role="form" id="form" name="form" autocomplete="off" novalidate rc-submit="signup()">
      <div class="form-group" ng-class="{'has-error':  rc.form.hasError(form.firstName)}">
          <label for="firstName">Your First Name</label>
          <input type="text" id="firstName" name="firstName" class="form-control input-sm" placeholder="First Name" ng-maxlength="40" required="required" ng-model="owner.name.first"/>
          <div class="help-block" ng-show="rc.form.hasError(form.firstName)">{{rc.form.getErrMsg(form.firstName)}}</div>
      </div>
      </form>
      

      javascript:

      //define custom submit directive
      var rcSubmitDirective = {
      'rcSubmit': ['$parse', function ($parse) {
          return {
              restrict: 'A',
              require: ['rcSubmit', '?form'],
              controller: ['$scope', function ($scope) {
                  this.attempted = false;
      
                  var formController = null;
      
                  this.setAttempted = function() {
                      this.attempted = true;
                  };
      
                  this.setFormController = function(controller) {
                    formController = controller;
                  };
      
                  this.hasError = function (fieldModelController) {
                      if (!formController) return false;
      
                      if (fieldModelController) {
                          return fieldModelController.$invalid && this.attempted;
                      } else {
                          return formController && formController.$invalid && this.attempted;
                      }
                  };
                  this.getErrMsg=function(ctrl){
                      var e=ctrl.$error;
                      var errMsg;
                      if (e.required){
                          errMsg='Please enter a value';
                      }
                      return errMsg;
                  }
              }],
              compile: function(cElement, cAttributes, transclude) {
                  return {
                      pre: function(scope, formElement, attributes, controllers) {
      
                          var submitController = controllers[0];
                          var formController = (controllers.length > 1) ? controllers[1] : null;
      
                          submitController.setFormController(formController);
      
                          scope.rc = scope.rc || {};
                          scope.rc[attributes.name] = submitController;
                      },
                      post: function(scope, formElement, attributes, controllers) {
      
                          var submitController = controllers[0];
                          var formController = (controllers.length > 1) ? controllers[1] : null;
                          var fn = $parse(attributes.rcSubmit);
      
                          formElement.bind('submit', function (event) {
                              submitController.setAttempted();
                              if (!scope.$$phase) scope.$apply();
      
                              if (!formController.$valid) return false;
      
                              scope.$apply(function() {
                                  fn(scope, {$event:event});
                              });
                          });
                      }
                };
              }
          };
      }]
      };
      app.directive(rcSubmitDirective);
      

      【讨论】:

        【解决方案10】:

        使用 angularjs 验证表单的完整解决方案。

        HTML如下。

        <div ng-app="areaApp" ng-controller="addCtrler">
                <form class="form-horizontal" name="fareainfo">
                    <div class="form-group">
                          <label for="input-areaname" class="col-sm-2 control-label">Area Name : </label>
                          <div class="col-sm-4">
                              <input type="text" class="form-control" name="name" id="input-areaname" ng-model="Area.Name" placeholder="" required>
                              <span class="text-danger" ng-show="(fareainfo.$submitted || fareainfo.name.$dirty) && fareainfo.name.$error.required"> Field is required</span>
                          </div>
                    </div>
                     <div class="col-sm-12">
                          <button type="button" class="btn btn-primary pull-right" ng-click="submitAreaInfo()">Submit</button>
                     </div>
                </form>
            </div>
        

        AngularJS App和Controller如下

        var areaApp = angular.module('areaApp', []); 
        areaApp.controller('addCtrler', function ($scope) {
            $scope.submitAreaInfo = function () {  
               if ($scope.fareainfo.$valid) {
                 //after Form is Valid
               } else {
                  $scope.fareainfo.$setSubmitted();
               }
            };
        });
        

        重要的代码段

        1. ng-app="areaApp" ng-controller="addCtrler"
          定义 Angular 应用和控制器

        2. ng-show="(fareainfo.$submitted || fareainfo.name.$dirty) && fareainfo.name.$error.required"
          上述条件确保每当用户第一次看到表单时屏幕上没有任何验证错误,并且在用户对表单进行更改后,它确保验证消息显示在屏幕上。 .name. 是输入元素的名称属性。

        3. $scope.fareainfo.$valid
          上面的代码,当用户提交表单时,分段检查表单是否有效。

        4. $scope.fareainfo.$setSubmitted();
          在上面的代码中,segment 确保每当用户提交表单而不做任何事情时,所有验证消息都会显示在屏幕上。

        【讨论】:

          【解决方案11】:
          // This worked for me.
          <form  name="myForm" class="css-form" novalidate ng-submit="Save(myForm.$invalid)">
          <input type="text" name="uName" ng-model="User.Name" required/>
          <span ng-show="User.submitted && myForm.uName.$error.required">Name is required.</span>
          <input ng-click="User.submitted=true" ng-disabled="User.submitted && tForm.$invalid" type="submit" value="Save" />
          </form>
          // in controller
          $scope.Save(invalid)
          {
          if(invalid) return;
          // save form
          }
          

          【讨论】:

            【解决方案12】:

            G45,

            我遇到了同样的问题,我已经创建了一个指令,请查看下面希望它可能会有所帮助

            指令:

                app.directive('formSubmitValidation', function () {
            
                    return {
                        require: 'form',
                        compile: function (tElem, tAttr) {
            
                            tElem.data('augmented', true);
            
                            return function (scope, elem, attr, form) {
                                elem.on('submit', function ($event) {
                                    scope.$broadcast('form:submit', form);
            
                                    if (!form.$valid) {
                                        $event.preventDefault();
                                    }
                                    scope.$apply(function () {
                                        scope.submitted = true;
                                    });
            
            
                                });
                            }
                        }
                    };
            
            
              })
            

            HTML:

            <form  name="loginForm" class="c-form-login" action="" method="POST" novalidate="novalidate" form-submit-validation="">
            
            <div class="form-group">
                                                            <input type="email" class="form-control c-square c-theme input-lg" placeholder="Email" ng-model="_username" name="_username" required>
                                                            <span class="glyphicon glyphicon-user form-control-feedback c-font-grey"></span>
                                                            <span ng-show="submitted || loginForm._username.$dirty && loginForm._username.$invalid">
                                                                <span ng-show="loginForm._username.$invalid" class="error">Please enter a valid email.</span>
                                                            </span>
                                                        </div>
            <button type="submit" class="pull-right btn btn-lg c-theme-btn c-btn-square c-btn-uppercase c-btn-bold">Login</button>
            </form>
            

            【讨论】:

              【解决方案13】:

              试试这个代码:

              <INPUT TYPE="submit" VALUE="Save" onClick="validateTester()">
              

              此功能将验证您的结果

              function validateTester() {
                  var flag = true
                  var Tester = document.forms.Tester
                  if (Tester.line1.value!="JavaScript") {
                      alert("First box must say 'JavaScript'!")
                      flag = false
                      }
                  if (Tester.line2.value!="Kit") {
                      alert("Second box must say 'Kit'!")
                      flag = false
                      }
                  if (flag) {
                      alert("Form is valid! Submitting form...")
                      document.forms.Tester.submit()
                      }
                  }
              

              【讨论】:

              • 对不起,我没有得到你的答案。什么是 Tester 对象?它是AngularJS中的东西吗?而且我不想弹出警报。只想显示隐藏的错误消息。谢谢你的回答
              猜你喜欢
              • 1970-01-01
              • 2023-03-12
              • 2020-01-22
              • 1970-01-01
              • 1970-01-01
              • 2019-02-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多