用户离开字段后validation字段

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


更新:

Angular现在提供了自定义模糊事件: https : //docs.angularjs.org/api/ng/directive/ngBlur

Angular 1.3现在有了ng-model-options,例如你可以将选项设置为{ 'updateOn': 'blur'} ,甚至当用户input的速度太快或者想要保存很less昂贵的DOM操作(如模型写入多个DOM位置,并且不希望每个关键点都发生$ digest循环)

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

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

并消除

您可以通过使用debounce键和ngModelOptions指令来延迟模型更新/validation。 这个延迟也适用于parsing器,validation器和模型标志,如$ dirty或$ pristine。

Ie ng-model-options =“{debounce:500}”将在上次内容更改后等待半秒,然后触发模型更新和表单validation。

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

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

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

我通过扩展@jlmcdonald的build议来解决这个问题。 我创build了一个自动应用于所有input和select元素的指令:

 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-focushas-visited类。 然后,您可以将这些类添加到您的CSS规则以显示validation错误:

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

这个效果很好,元素仍然会获得$ invalid属性等,但是CSS可以用来给用户一个更好的体验。

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

 :focus ~ .error { display:none; } 

在满足这两个要求之后,这将隐藏任何与重点input字段有关的错误消息,我认为angularjs应该做的事情。 看起来像一个疏忽。

这似乎是在更新版本的angular度中实现的标准。

ng-untouchedng-touch的类分别在用户关注一个validation元素之前和之后设置。

CSS

 input.ng-touched.ng-invalid { border-color: red; } 

关于@ lambinator的解决scheme…我在angular.js 1.2.4中得到以下错误:

错误:[$ rootScope:inprog] $摘要已在进行中

我不确定我是否做错了什么,或者如果这是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); 

它可能会为你写一个封装了javascript blur()方法的自定义指令(并在触发时运行validation函数); 有一个Angular问题有一个示例(以及一个通用指令,可以绑定到Angular本身不支持的其他事件):

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

如果你不想走这条路线,你的另一个select是在现场设置$ watch,当填写完该字段后再次触发validation。

要进一步了解给定的答案,可以通过使用CSS3伪类简化input标记,并仅使用类标记访问的字段,以延迟显示validation错误,直到用户失去焦点在字段上:

(例子需要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> 

基于@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; } 

这里是一个使用ng-messages(angular1.3)和自定义指令的例子。

validation消息在第一次用户离开input域时显示在模糊上,但是当他纠正该值时,validation消息立即被移除(不再模糊)。

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']); 

AngularJS 1.3中的ng-model-options(本文写作时的beta)被logging为支持{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> 

您可以使用ng-class和相关控制器范围的属性来dynamic设置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; }; 

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

 :focus ~ .form-control-feedback.glyphicon-ok { display:none; } :focus ~ .form-control-feedback.glyphicon-remove { display:none; } .has-feedback > :focus { & { .form-control-focus(); } } 

outI使用了一个指令。 这里是代码:

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

我的所有input控件都有一个span元素作为下一个元素,这是我的validation消息的显示位置,所以作为属性的指令被添加到每个input控件中。

我也有(可选的).has-focus和has-visited css class在我的css文件中,你看到在指令中被引用。

注意:请记住添加“on-blur-val”正是这种方式到您的input控件没有撇号

通过使用ng-focus,你可以实现你的目标。 您需要在input字段中提供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>

我们可以使用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

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

 <div ng-show="formName.firstName.$touched && formName.firstName.$error.required"> You must enter a value </div>