我已经使用AngularJS创建了一个HTML表单,并在某些字段中添加了必需的属性。
对于这些字段,我有一个错误消息,显示如果该字段不是$ pristine,也$无效:
<input type="text" ng-model="SomeModel.SomeProperty" name="myField" class="input-block-level" required> <p ng-show="frmMyForm.myField.$invalid && !frmMyForm.myField.$pristine" class="error-text">This field is required!</p>
这工作正常但是,如果用户只需跳过必填字段(永远不要将光标放在其中),则该字段始终是原始的,因此即使在单击提交按钮之后,也不会显示错误消息。所以用户面临着无法提交的表单,但没有错误的文字告诉他们为什么。
我的想法是,在提交操作中将所有表单字段设置为$ dirty将触发错误消息,以显示用户简单跳过的任何必填字段。这可能吗?如果是这样,怎么办?
提前致谢。
我们做一些类似于你的答案,我们有一个formSubmitted指令绑定到提交事件,如果触发我们在表单控制器上设置$ submitted变量。这样,您可以以与使用ShowValidationMessages的方式相似的方式使用它,但可重复使用。非常简单的指令:
app.directive('formSubmitted',[function () { return { restrict: 'A',require: 'form',link: function (scope,element,attrs,ctrl) { ctrl.$submitted = false; element.on('submit',function () { scope.$apply(function () { ctrl.$submitted = true; }); }); } }; }]);
我们进一步介绍了几个步骤,我们的要求是仅在以下条件成立时才显示验证错误:元素无效,或者表单被提交或输入元素模糊。所以我们结束了另一个指令,要求ngModel在ngModel控制器上设置元素的模糊状态。
最后在html中排除大量重复的锅炉代码,以检查所有这些事情,例如你的ng-show =“frmMyForm.myField。$ invalid&&(!frmMyForm.myField。$ pristine || MyObject.ShowValidationMessages)”我们也将它封装到一个指令中。这个模板指令用Bootstrap锅炉板包装我们的输入元素,并处理所有的验证内容。所以现在我所有的表单输入都遵循这种模式:
<div data-bc-form-group data-label="Username:"> <input type="text" id="username" name="username" ng-model="vm.username" data-bc-focus required /> </div>
并且bcFormGroup指令将其转换为启用以下引导的html:
<div class="form-group" ng-class="{'has-error': showFormGroupError()}" data-bc-form-group="" data-label="Username:"> <label for="username" class="col-md-3 control-label ng-binding">Username:</label> <div class="col-md-9"> <input type="text" id="username" name="username" ng-model="vm.username" data-bc-focus="" required="" class="ng-pristine form-control ng-valid ng-valid-required"> <span class="help-block ng-hide" ng-show="showrequiredError()">required</span> </div> </div>
这样可以保持DRY,并为支持哪种类型的输入提供极大的灵活性。
更新:
这是bcFormGroup指令的基本列表。默认模板使用引导的水平形式,但可以适应您的喜好。
app.directive('bcFormGroup',['$compile','$interpolate',function ($compile,$interpolate) { return { restrict: 'A',template: '<div class="form-group" ng-class="{\'has-error\': showFormGroupError()}">' + '<label for="{{inputId}}" class="col-md-3 control-label">{{label}}</label>' + '<div class="col-md-9">' + '<bc-placeholder></bc-placeholder>' + '</div>' + '</div>',replace: true,transclude: true,require: '^form',scope: { label: '@',inputTag: '@' },formController,transcludeFn) { transcludeFn(function (clone) { var placeholder = element.find('bc-placeholder'); placeholder.replaceWith(clone); }); var inputTagType = scope.inputTag || 'input'; var inputElement = element.find(inputTagType); var fqFieldName = formController.$name + '.' + inputElement.attr('name'); var formScope = inputElement.scope(); if (inputElement.attr('type') !== 'checkBox' && inputElement.attr('type') !== 'file') { inputElement.addClass('form-control'); } scope.inputId = $interpolate(inputElement.attr('id'))(formScope); scope.hasError = false; scope.submitted = false; formScope.$watch(fqFieldName + '.$invalid',function (hasError) { scope.hasError = hasError; }); formScope.$watch(formController.$name + '.$submitted',function (submitted) { scope.submitted = submitted; }); if (inputElement.attr('data-bc-focus') != null || inputElement.attr('bc-focus') != null) { scope.hasBlurred = false; formScope.$watch(fqFieldName + '.$hasBlurred',function (hasBlurred) { scope.hasBlurred = hasBlurred; }); } if (inputElement.attr('required')) { scope.hasrequiredError = false; formScope.$watch(fqFieldName + '.$error.required',function (required) { scope.hasrequiredError = required; }); inputElement.after($compile('<span class="help-block" ng-show="showrequiredError()">required</span>')(scope)); } if (inputElement.attr('type') === 'email') { scope.hasEmailError = false; formScope.$watch(fqFieldName + '.$error.email',function (emailError) { scope.hasEmailError = emailError; }); inputElement.after($compile('<span class="help-block" ng-show="showEmailError()">Invalid email address</span>')(scope)); } scope.showFormGroupError = function () { return scope.hasError && (scope.submitted || (scope.hasBlurred === true)); }; scope.showrequiredError = function () { return scope.hasrequiredError && (scope.submitted || (scope.hasBlurred === true)); }; scope.showEmailError = function () { return scope.hasEmailError && (scope.submitted || (scope.hasBlurred === true)); }; } }; }]);
更新:
以下指令设置$ focus和$ hasBlurred:
app.directive('bcFocus',[function () { var focusClass = 'bc-focused'; return { restrict: 'A',require: 'ngModel',ctrl) { ctrl.$focused = false; ctrl.$hasBlurred = false; element.on('focus',function () { element.addClass(focusClass); var phase = scope.$root.$$phase; if (phase == '$apply' || phase == '$digest') { ctrl.$focused = true; } else { scope.$apply(function () { ctrl.$focused = true; }); } }).on('blur',function () { element.removeClass(focusClass); var phase = scope.$root.$$phase; if (phase == '$apply' || phase == '$digest') { ctrl.$focused = false; ctrl.$hasBlurred = true; } else { scope.$apply(function () { ctrl.$focused = false; ctrl.$hasBlurred = true; }); } }); } }; }]);