94

使用 AngularJS,我可以使用ng-pristineorng-dirty来检测用户是否输入了该字段。但是,我只想在用户离开字段区域后进行客户端验证。这是因为当用户输入诸如电子邮件或电话之类的字段时,他们总是会收到一个错误,直到他们完成输入完整的电子邮件,这并不是最佳的用户体验。

例子


更新:

Angular 现在附带一个自定义模糊事件: https ://docs.angularjs.org/api/ng/directive/ngBlur

4

17 回答 17

93

从 1.3.0 版本开始,这可以很容易地用 来完成$touched,这在用户离开现场后是正确的。

<p ng-show="form.field.$touched && form.field.$invalid">Error</p>

https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

于 2014-10-06T07:44:52.057 回答
75

Angular 1.3 现在有 ng-model-options,你可以将选项设置{ 'updateOn': 'blur'}为例如,你甚至可以去抖动,当使用时输入太快,或者你想节省一些昂贵的 DOM 操作(比如模型编写到多个 DOM 位置,并且您不希望每次按键都发生 $digest 循环)

https://docs.angularjs.org/guide/forms#custom-triggershttps://docs.angularjs.org/guide/forms#non-immediate-debounced-model-updates

默认情况下,对内容的任何更改都会触发模型更新和表单验证。您可以使用 ngModelOptions 指令覆盖此行为,以仅绑定到指定的事件列表。即 ng-model-options="{ updateOn: 'blur' }" 只有在控件失去焦点后才会更新和验证。您可以使用空格分隔的列表设置多个事件。即 ng-model-options="{ updateOn: 'mousedown blur' }"

并去抖动

您可以使用带有 ngModelOptions 指令的 debounce 键来延迟模型更新/验证。这种延迟也适用于解析器、验证器和模型标志,如 $dirty 或 $pristine。

即 ng-model-options="{ debounce: 500 }" 在触发模型更新和表单验证之前,将在最后一次内容更改后等待半秒。

于 2014-05-04T23:37:54.430 回答
32

我通过扩展@jlmcdonald 的建议解决了这个问题。我创建了一个指令,该指令将自动应用于所有输入和选择元素:

var blurFocusDirective = function () {
    return {
        restrict: 'E',
        require: '?ngModel',
        link: function (scope, elm, attr, ctrl) {
            if (!ctrl) {
                return;
            }

            elm.on('focus', function () {
                elm.addClass('has-focus');

                scope.$apply(function () {
                    ctrl.hasFocus = true;
                });
            });

            elm.on('blur', function () {
                elm.removeClass('has-focus');
                elm.addClass('has-visited');

                scope.$apply(function () {
                    ctrl.hasFocus = false;
                    ctrl.hasVisited = true;
                });
            });

            elm.closest('form').on('submit', function () {
                elm.addClass('has-visited');

                scope.$apply(function () {
                    ctrl.hasFocus = false;
                    ctrl.hasVisited = true;
                });
            });

        }
    };
};

app.directive('input', blurFocusDirective);
app.directive('select', blurFocusDirective);

当用户关注/访问元素时,这将为各种元素添加has-focus和分类。has-visited然后,您可以将这些类添加到您的 CSS 规则中以显示验证错误:

input.has-visited.ng-invalid:not(.has-focus) {
    background-color: #ffeeee;   
}

这在元素仍然获得 $invalid 属性等方面效果很好,但 CSS 可用于为用户提供更好的体验。

于 2013-06-04T18:28:18.440 回答
17

我设法用一个非常简单的 CSS 来做到这一点。这确实要求错误消息是与它们相关的输入的兄弟,并且它们具有error.

:focus ~ .error {
    display:none;
}

在满足这两个要求之后,这将隐藏与焦点输入字段相关的任何错误消息,我认为 angularjs 无论如何都应该这样做。似乎是一个疏忽。

于 2014-01-27T20:19:24.257 回答
5

这似乎在较新版本的 Angular 中作为标准实现。

ng-untouchedng-touched类分别在用户关注已验证元素之前和之后设置。

CSS

input.ng-touched.ng-invalid {
   border-color: red;
}
于 2014-09-24T09:35:32.663 回答
4

关于@lambinator 的解决方案...我在 angular.js 1.2.4 中收到以下错误:

错误:[$rootScope:inprog] $digest 已经在进行中

我不确定我是否做错了什么,或者这是否是 Angular 的更改,但删除scope.$apply语句解决了问题,并且类/状态仍在更新。

如果您也看到此错误,请尝试以下操作:

var blurFocusDirective = function () {
  return {
    restrict: 'E',
    require: '?ngModel',
    link: function (scope, elm, attr, ctrl) {
      if (!ctrl) {
        return;
      }
      elm.on('focus', function () {
        elm.addClass('has-focus');
        ctrl.$hasFocus = true;
      });

      elm.on('blur', function () {
        elm.removeClass('has-focus');
        elm.addClass('has-visited');
        ctrl.$hasFocus = false;
        ctrl.$hasVisited = true;
      });

      elm.closest('form').on('submit', function () {
        elm.addClass('has-visited');

        scope.$apply(function () {
          ctrl.hasFocus = false;
          ctrl.hasVisited = true;
        });
      });
    }
  };
};
app.directive('input', blurFocusDirective);
app.directive('select', blurFocusDirective);
于 2013-12-08T19:54:47.917 回答
2

编写一个包装 javascript blur() 方法的自定义指令(并在触发时运行验证函数)可能对您有用;有一个 Angular 问题有一个示例问题(以及一个可以绑定到 Angular 本身不支持的其他事件的通用指令):

https://github.com/angular/angular.js/issues/1277

如果您不想走那条路,您的另一个选择是在该字段上设置 $watch ,在填写该字段时再次触发验证。

于 2013-04-03T22:13:02.310 回答
2

为了进一步了解给定的答案,您可以通过使用 CSS3 伪类来简化输入标记,并且只使用类标记访问的字段以延迟显示验证错误,直到用户失去对字段的关注:

(示例需要 jQuery)

JavaScript

module = angular.module('app.directives', []);
module.directive('lateValidateForm', function () {
    return {
        restrict: 'AC',
        link: function (scope, element, attrs) {
            $inputs = element.find('input, select, textarea');

            $inputs.on('blur', function () {
                $(this).addClass('has-visited');
            });

            element.on('submit', function () {
                $inputs.addClass('has-visited');
            });
        }
    };
});

CSS

input.has-visited:not(:focus):required:invalid,
textarea.has-visited:not(:focus):required:invalid,
select.has-visited:not(:focus):required:invalid {
  color: #b94a48;
  border-color: #ee5f5b;
}

HTML

<form late-validate-form name="userForm">
  <input type="email" name="email" required />
</form>
于 2013-06-05T14:14:36.393 回答
2

基于@nicolas的回答..纯CSS应该是诀窍,它只会在模糊时显示错误消息

<input type="email" id="input-email" required
               placeholder="Email address" class="form-control" name="email"
               ng-model="userData.email">
        <p ng-show="form.email.$error.email" class="bg-danger">This is not a valid email.</p>

CSS

.ng-invalid:focus ~ .bg-danger {
     display:none;
}
于 2014-03-21T06:12:03.820 回答
2

这是一个使用 ng-messages(在 angular 1.3 中可用)和自定义指令的示例。

用户第一次离开输入字段时,验证消息会显示在模糊上,但是当他更正值时,验证消息会立即被删除(不再模糊)。

JavaScript

myApp.directive("validateOnBlur", [function() {
    var ddo = {
        restrict: "A",
        require: "ngModel",
        scope: {},
        link: function(scope, element, attrs, modelCtrl) {
            element.on('blur', function () {
                modelCtrl.$showValidationMessage = modelCtrl.$dirty;
                scope.$apply();
            });
        }
    };
    return ddo;
}]);

HTML

<form name="person">
    <input type="text" ng-model="item.firstName" name="firstName" 
        ng-minlength="3" ng-maxlength="20" validate-on-blur required />
    <div ng-show="person.firstName.$showValidationMessage" ng-messages="person.firstName.$error">
        <span ng-message="required">name is required</span>
        <span ng-message="minlength">name is too short</span>
        <span ng-message="maxlength">name is too long</span>
    </div>
</form>

PS。不要忘记下载 ngMessages 并将其包含在您的模块中:

var myApp = angular.module('myApp', ['ngMessages']);
于 2014-08-06T10:44:01.043 回答
1

AngularJS 1.3(撰写本文时为测试版)中的 ng-model-options 被记录为支持 {updateOn: 'blur'}。对于早期版本,以下内容对我有用:

myApp.directive('myForm', function() {
  return {
    require: 'form',
    link: function(scope, element, attrs, formController) {
      scope.validate = function(name) {
        formController[name].isInvalid
            = formController[name].$invalid;
      };
    }
  };
});

使用这样的模板:

<form name="myForm" novalidate="novalidate" data-my-form="">
<input type="email" name="eMail" required="required" ng-blur="validate('eMail')" />
<span ng-show="myForm.eMail.isInvalid">Please enter a valid e-mail address.</span>
<button type="submit">Submit Form</button>
</form>
于 2014-05-22T18:22:53.403 回答
1

使用字段状态$touched该字段已被触摸,如下例所示。

<div ng-show="formName.firstName.$touched && formName.firstName.$error.required">
    You must enter a value
</div>
于 2017-04-20T08:36:52.133 回答
0

您可以使用 ng-class 和关联控制器范围内的属性动态设置 has-error css 类(假设您使用的是引导程序):

plunkr:http ://plnkr.co/edit/HYDlaTNThZE02VqXrUCH?p=info

HTML:

<div ng-class="{'has-error': badEmailAddress}">
    <input type="email" class="form-control" id="email" name="email"
        ng-model="email" 
        ng-blur="emailBlurred(email.$valid)">
</div>

控制器:

$scope.badEmailAddress = false;

$scope.emailBlurred = function (isValid) {
    $scope.badEmailAddress = !isValid;
};
于 2014-04-29T17:43:07.767 回答
0

如果您使用 bootstrap 3 和 lesscss,您可以使用以下 less 代码段启用模糊验证:

:focus ~ .form-control-feedback.glyphicon-ok {
  display:none;
}

:focus ~ .form-control-feedback.glyphicon-remove {
  display:none;
}

.has-feedback > :focus {
  & {
    .form-control-focus();
  }
}
于 2014-06-23T09:32:13.997 回答
0

out我使用了一个指令。这是代码:

app.directive('onBlurVal', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs, controller) {

            element.on('focus', function () {
                element.next().removeClass('has-visited');
                element.next().addClass('has-focus');
            });

            element.on('blur', function () {

                element.next().removeClass('has-focus');
                element.next().addClass('has-visited');
            });
        }
    }
})

我的所有输入控件都有一个 span 元素作为下一个元素,这是显示我的验证消息的地方,因此将指令作为属性添加到每个输入控件中。

我的 css 文件中还有(可选).has-focus 和 has-visited css 类,您可以在指令中看到它们被引用。

注意:请记住以这种方式将“on-blur-val”添加到您的输入控件中,不要使用撇号

于 2014-07-04T19:26:33.080 回答
0

通过使用ng-focus,您可以实现您的目标。您需要在输入字段中提供 ng-focus 。在编写您的 ng-show 衍生品时,您还必须编写一个不相等的逻辑。像下面的代码:

<input type="text" class="form-control" name="inputPhone" ng-model="demo.phoneNumber" required ng-focus> <div ng-show="demoForm.inputPhone.$dirty && demoForm.inputPhone.$invalid && !demoForm.inputPhone.$focused"></div>

于 2014-09-10T13:02:13.030 回答
0

我们可以使用 onfocus 和 onblur 函数。将是简单和最好的。

<body ng-app="formExample">
  <div ng-controller="ExampleController">
  <form novalidate class="css-form">
    Name: <input type="text" ng-model="user.name" ng-focus="onFocusName='focusOn'" ng-blur="onFocusName=''" ng-class="onFocusName" required /><br />
    E-mail: <input type="email" ng-model="user.email" ng-focus="onFocusEmail='focusOn'" ng-blur="onFocusEmail=''" ng-class="onFocusEmail" required /><br />
  </form>
</div>

<style type="text/css">
 .css-form input.ng-invalid.ng-touched {
    border: 1px solid #FF0000;
    background:#FF0000;
   }
 .css-form input.focusOn.ng-invalid {
    border: 1px solid #000000;
    background:#FFFFFF;
 }
</style>

在这里试试:

http://plnkr.co/edit/NKCmyru3knQiShFZ96tp?p=preview

于 2015-11-24T07:49:09.377 回答