协调Angular.js和Bootstrap表单validation样式

我正在使用Angular和Bootstrap。 以下是供参考的代码:

<form name="newUserForm" ng-submit="add()" class="" novalidate> <input type="text" class="input" ng-model="newUser.uname" placeholder="Twitter" ng-pattern="/^@[A-Za-z0-9_]{1,15}$/" required></td> <button type="submit" ng-disabled="newUserForm.$invalid" class="btn btn-add btn-primary">Add</button> </form> 

Bootstrap以无效字段的formsinput:invalid {.... } ; 当领域是空的时候这些踢。 现在我也有一些通过Angular进行模式匹配。 这会在“:invalid”closures时创build奇怪的情况,但“.ng-invalid”处于打开状态,这将要求我为“.ng-invalid”类重新实现引导CSS类。

我看到两个选项,但是两者都有问题

  • 使Angular使用一些自定义的类名而不是“ng-valid”(我不知道该怎么做)。
  • 禁用html5validation(我认为这就是表单标签中的“novalidate”属性应该做的,但由于某种原因无法工作)。

Angular-Bootstrap指令不包含样式。

使用Bootstrap的“错误”类的样式。 你可以写更less的代码。

 <form name="myForm"> <div class="control-group" ng-class="{error: myForm.name.$invalid}"> <label>Name</label> <input type="text" name="name" ng-model="project.name" required> <span ng-show="myForm.name.$error.required" class="help-inline"> Required</span> </div> </form> 

编辑:其他答案和评论指出 – 在Bootstrap 3类现在是“有错误”,而不是“错误”。

Bootstrap 3中的类已经更改:

 <form class="form-horizontal" name="form" novalidate ng-submit="submit()" action="/login" method="post"> <div class="row" ng-class="{'has-error': form.email.$invalid, 'has-success': !form.email.$invalid}"> <label for="email" class="control-label">email:</label> <div class="col"> <input type="email" id="email" placeholder="email" name="email" ng-model="email" required> <p class="help-block error" ng-show="form.email.$dirty && form.email.$error.required">please enter your email</p> <p class="help-block error" ng-show="form.email.$error.email">please enter a valid email</p> ... 

注意'has-error''has-success'的引号:花了一段时间才发现…

另一个解决scheme:创build指令,根据子input切换has-error类。

 app.directive('bsHasError', [function() { return { restrict: "A", link: function(scope, element, attrs, ctrl) { var input = element.find('input[ng-model]'); if (input.length) { scope.$watch(function() { return input.hasClass('ng-invalid'); }, function(isInvalid) { element.toggleClass('has-error', isInvalid); }); } } }; }]); 

然后在模板中使用它

 <div class="form-group" bs-has-error> <input class="form-control" ng-model="foo" ng-pattern="/.../"/> </div> 

@ farincz的答案略有改善。 我同意一个指令是最好的方法,但我不想在每个.form-group元素上重复它,所以我更新了代码,以允许将它添加到.form-group或父级<form>元素(将它添加到所有包含的.form-group元素):

 angular.module('directives', []) .directive('showValidation', [function() { return { restrict: "A", link: function(scope, element, attrs, ctrl) { if (element.get(0).nodeName.toLowerCase() === 'form') { element.find('.form-group').each(function(i, formGroup) { showValidation(angular.element(formGroup)); }); } else { showValidation(element); } function showValidation(formGroupEl) { var input = formGroupEl.find('input[ng-model],textarea[ng-model]'); if (input.length > 0) { scope.$watch(function() { return input.hasClass('ng-invalid'); }, function(isInvalid) { formGroupEl.toggleClass('has-error', isInvalid); }); } } } }; }]); 

@安德鲁·史密斯的答案略有改善。 我更改input元素并使用require关键字。

 .directive('showValidation', [function() { return { restrict: "A", require:'form', link: function(scope, element, attrs, formCtrl) { element.find('.form-group').each(function() { var $formGroup=$(this); var $inputs = $formGroup.find('input[ng-model],textarea[ng-model],select[ng-model]'); if ($inputs.length > 0) { $inputs.each(function() { var $input=$(this); scope.$watch(function() { return $input.hasClass('ng-invalid'); }, function(isInvalid) { $formGroup.toggleClass('has-error', isInvalid); }); }); } }); } }; }]); 

感谢@farincz提供了一个很好的答案。 这里有一些修改我已经适合我的用例。

这个版本提供了三个指令:

  • bs-has-success
  • bs-has-error
  • bs-has (当你想把另外两个一起使用的时候方便)

我所做的修改:

  • 添加了一个检查,只有当表单域是脏的时候才显示有状态,也就是说直到有人与它们交互时才会显示。
  • 改变了传递给不使用jQuery的element.find()的stringelement.find() ,因为Angular的jQLite中的element.find()只支持通过标记名查找元素。
  • 增加了对select框和textareas的支持。
  • $timeout包装element.find()以支持元素可能还没有将其子元素呈现给DOM的情况(例如,如果元素的子元素用ng-if标记)。
  • ifexpression式检查返回的数组的长度( if(input)来自@ farincz的答案总是返回true,因为从element.find()返回的是一个jQuery数组)。

我希望有人认为这有用!

 angular.module('bs-has', []) .factory('bsProcessValidator', function($timeout) { return function(scope, element, ngClass, bsClass) { $timeout(function() { var input = element.find('input'); if(!input.length) { input = element.find('select'); } if(!input.length) { input = element.find('textarea'); } if (input.length) { scope.$watch(function() { return input.hasClass(ngClass) && input.hasClass('ng-dirty'); }, function(isValid) { element.toggleClass(bsClass, isValid); }); } }); }; }) .directive('bsHasSuccess', function(bsProcessValidator) { return { restrict: 'A', link: function(scope, element) { bsProcessValidator(scope, element, 'ng-valid', 'has-success'); } }; }) .directive('bsHasError', function(bsProcessValidator) { return { restrict: 'A', link: function(scope, element) { bsProcessValidator(scope, element, 'ng-invalid', 'has-error'); } }; }) .directive('bsHas', function(bsProcessValidator) { return { restrict: 'A', link: function(scope, element) { bsProcessValidator(scope, element, 'ng-valid', 'has-success'); bsProcessValidator(scope, element, 'ng-invalid', 'has-error'); } }; }); 

用法:

 <!-- Will show success and error states when form field is dirty --> <div class="form-control" bs-has> <label for="text"></label> <input type="text" id="text" name="text" ng-model="data.text" required> </div> <!-- Will show success state when select box is anything but the first (placeholder) option --> <div class="form-control" bs-has-success> <label for="select"></label> <select id="select" name="select" ng-model="data.select" ng-options="option.name for option in data.selectOptions" required> <option value="">-- Make a Choice --</option> </select> </div> <!-- Will show error state when textarea is dirty and empty --> <div class="form-control" bs-has-error> <label for="textarea"></label> <textarea id="textarea" name="textarea" ng-model="data.textarea" required></textarea> </div> 

您也可以安装Guilherme的凉亭包 ,将所有这些捆绑在一起。

如果样式是问题,但不想禁用本机validation,为什么不用自己的, 更具体的样式重写样式?

 input.ng-invalid, input.ng-invalid:invalid { background: red; /*override any styling giving you fits here*/ } 

使用CSSselect器特性级联您的问题!

我对Jason Im的回答改进如下,增加了两个新的指令show-validation-errors和show-validation-error。

 'use strict'; (function() { function getParentFormName(element,$log) { var parentForm = element.parents('form:first'); var parentFormName = parentForm.attr('name'); if(!parentFormName){ $log.error("Form name not specified!"); return; } return parentFormName; } angular.module('directives').directive('showValidation', function () { return { restrict: 'A', require: 'form', link: function ($scope, element) { element.find('.form-group').each(function () { var formGroup = $(this); var inputs = formGroup.find('input[ng-model],textarea[ng-model],select[ng-model]'); if (inputs.length > 0) { inputs.each(function () { var input = $(this); $scope.$watch(function () { return input.hasClass('ng-invalid') && !input.hasClass('ng-pristine'); }, function (isInvalid) { formGroup.toggleClass('has-error', isInvalid); }); $scope.$watch(function () { return input.hasClass('ng-valid') && !input.hasClass('ng-pristine'); }, function (isInvalid) { formGroup.toggleClass('has-success', isInvalid); }); }); } }); } }; }); angular.module('directives').directive('showValidationErrors', function ($log) { return { restrict: 'A', link: function ($scope, element, attrs) { var parentFormName = getParentFormName(element,$log); var inputName = attrs['showValidationErrors']; element.addClass('ng-hide'); if(!inputName){ $log.error("input name not specified!") return; } $scope.$watch(function () { return !($scope[parentFormName][inputName].$dirty && $scope[parentFormName][inputName].$invalid); },function(noErrors){ element.toggleClass('ng-hide',noErrors); }); } }; }); angular.module('friport').directive('showValidationError', function ($log) { return { restrict: 'A', link: function ($scope, element, attrs) { var parentFormName = getParentFormName(element,$log); var parentContainer = element.parents('*[show-validation-errors]:first'); var inputName = parentContainer.attr('show-validation-errors'); var type = attrs['showValidationError']; element.addClass('ng-hide'); if(!inputName){ $log.error("Could not find parent show-validation-errors!"); return; } if(!type){ $log.error("Could not find validation error type!"); return; } $scope.$watch(function () { return !$scope[parentFormName][inputName].$error[type]; },function(noErrors){ element.toggleClass('ng-hide',noErrors); }); } }; }); })(); 

show-validation-errors可以被添加到一个错误容器中,以便根据表单字段的有效性显示/隐藏容器。

并且show-validation-error显示或隐藏基于给定types的表单字段有效性的元素。

预期用途的一个例子:

  <form role="form" name="organizationForm" novalidate show-validation> <div class="form-group"> <label for="organizationNumber">Organization number</label> <input type="text" class="form-control" id="organizationNumber" name="organizationNumber" required ng-pattern="/^[0-9]{3}[ ]?[0-9]{3}[ ]?[0-9]{3}$/" ng-model="organizationNumber"> <div class="help-block with-errors" show-validation-errors="organizationNumber"> <div show-validation-error="required"> Organization number is required. </div> <div show-validation-error="pattern"> Organization number needs to have the following format "000 000 000" or "000000000". </div> </div> </div> </form> 

我想现在回复已经太迟了,但是希望你会爱上它:

CSS可以添加其他types的控件,如select,date,密码等

 input[type="text"].ng-invalid{ border-left: 5px solid #ff0000; background-color: #FFEBD6; } input[type="text"].ng-valid{ background-color: #FFFFFF; border-left: 5px solid #088b0b; } input[type="text"]:disabled.ng-valid{ background-color: #efefef; border: 1px solid #bbb; } 

HTML :除ng之外,不需要在控件中添加任何东西,如果是的话

 <input type="text" class="form-control" ng-model="customer.ZipCode" ng-required="true"> 

只要尝试一下,在你的控制中键入一些文字,我发现它真的很方便,很棒。

很难说没有小提琴,但看着angular.js代码,它不会取代类 – 它只是增加和删除它自己的。 因此,任何引导类(由引导UI脚本dynamic添加)都应该不受angular度影响。

也就是说,在Angular的同时使用Bootstrap的JSfunction进行validation是没有意义的 – 只能使用Angular。 我build议你采用引导样式和angularJS,即使用自定义validation指令将引导CSS类添加到您的元素。

 <div class="form-group has-feedback" ng-class="{ 'has-error': form.uemail.$invalid && form.uemail.$dirty }"> <label class="control-label col-sm-2" for="email">Email</label> <div class="col-sm-10"> <input type="email" class="form-control" ng-model="user.email" name="uemail" placeholder="Enter email" required> <div ng-show="form.$submitted || form.uphone.$touched" ng-class="{ 'has-success': form.uemail.$valid && form.uemail.$dirty }"> <span ng-show="form.uemail.$valid" class="glyphicon glyphicon-ok-sign form-control-feedback" aria-hidden="true"></span> <span ng-show="form.uemail.$invalid && form.uemail.$dirty" class="glyphicon glyphicon-remove-circle form-control-feedback" aria-hidden="true"></span> </div> </div> </div> 

我知道这是一个非常古老的问题答案线程,当我没有听说AngularJS本身的名称:-)

但对于其他人来到这个页面寻找Angular + Bootstrap表单validation的干净和自动化的方式,我已经写了一个很小的模块来实现相同的,而不改变任何forms的HTML或Javascript。

结帐Bootstrapangular度validation 。

以下是三个简单的步骤:

  1. 通过Bower bower install bootstrap-angular-validation --save
  2. 添加脚本文件<script src="bower_components/bootstrap-angular-validation/dist/bootstrap-angular-validation.min.js"></script>
  3. 添加依赖bootstrap.angular.validation到你的应用程序, 就是这样!

这适用于Bootstrap 3, jQuery 不是必需的

这是基于jQueryvalidation的概念。 该模块提供了一些validation错误的附加validation和通用通用消息。