在 angularjs 中提交时显示验证错误消息

IT技术 javascript validation angularjs
2021-02-17 23:38:42

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

这是一个工作的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

6个回答

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

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

submitted && form.email.$error.required

更新

正如@Hafez的评论中所指出(给他一些赞成票!),Angular 1.3+ 解决方案很简单:

form.$submitted && form.email.$error.required
@Chandermani:你能帮我这个链接吗?stackoverflow.com/questions/29557554/...
2021-04-23 23:38:42
是的,这个解决方案并不虔诚,在 Angular 1.3 之后。现在有一个 $submitted 属性。
2021-05-05 23:38:42
该解决方案有效,但我认为对于正常用例,它不能满足要求,该错误也应出现在 form.email.$touched && form.email.$error.required 中,因此是实现的最佳方法结果是将验证留给控制器方法,检查表单验证然后为每个属性调用 $setTouched。
2021-05-08 23:38:42
@Chandermani 只是想说,请在您的工作 plunker 中包含 novalidate。:)
2021-05-10 23:38:42
只需form.$submitted根据文档docs.angularjs.org/guide/...使用即可
2021-05-15 23:38:42

由于我使用的是 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'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();
          }
        })
      ;

    }
  };
}])

然后在 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;
*/
}

简单得多!

稍微修改以需要表单控制器。现在,您只能在 a 上组合 validSubmit 指令,<form>而不必再手动从作用域中获取控制器。更新了 jsfiddle
2021-04-28 23:38:42
@Plantface 我将您的指令与另一个指令组合在一起,该指令循环遍历所有表单组 div 并监视输入,以便在验证状态更改时设置它们的 has-error 类。gist.github.com/anonymous/97efc4f2f12ba51c5cf3
2021-05-04 23:38:42
还有一个更新,现在包括对第一个输入(和一些评论)的自动对焦:新的 jsfiddle
2021-05-07 23:38:42
不妨在这里放一个最终版本:final jsfiddle
2021-05-07 23:38:42
非常好!我对其进行了一些改进,并在此jsfiddl 中提供了具有 Bootstrap 3 风格的示例
2021-05-10 23:38:42

我也遇到了同样的问题,我通过添加一个 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 ;)

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

第一个是删除novalidate以启用浏览器的验证。

其次,save当表单无效时,您可以禁用该按钮,如下所示

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

希望能帮助到你。

谢谢,在 safari ios 浏览器中删除 novalidate 会带来麻烦。它不提供验证弹出窗口。如果最初禁用提交按钮,对我(用户)来说也没什么含糊之处。但这是处理它的好方法。
2021-05-12 23:38:42

有两种简单而优雅的方法可以做到。

纯 CSS:

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

我们可以使用.ng-submittedCSS 来控制我们的元素。

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

.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
2021-05-12 23:38:42