协调 Angular.js 和 Bootstrap 表单验证样式

我正在使用与 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 为 input:invalid {.... }形式的无效字段提供了样式; 当字段为空时,这些样式就会生效。现在我也有一些通过 Angular 的模式匹配。这样就会产生奇怪的情况,当“ : void”关闭时,但是“。“ n- 无效”处于打开状态,这需要我重新实现“。“ n- 无效”类。

我看到两个选择,但都有问题

  • 使 Angular 使用一些自定义的类名而不是“ ng-valid”(我不知道如何做到这一点)。
  • 禁用 html5验证(我认为表单标记中的“ novalid”属性应该这样做,但由于某些原因无法正常工作)。

那里的角引导指令不涵盖样式。

59458 次浏览

如果没有小提琴,很难确定,但是看看 angular.js 代码,它不会替换类——它只是添加和删除自己的类。因此,任何引导类(由引导程序 UI 脚本动态添加)都不应受到角度的影响。

也就是说,在验证时使用 Bootstrap 的 JS 功能与只使用 Angular 的 JS 功能是没有意义的。我建议您使用 bootstrap 样式和有角度的 JS,即使用自定义验证指令将 bootstrap css 类添加到元素中。

如果样式是问题所在,但您不想禁用本机验证,为什么不用自己的 具体点样式重写样式呢?

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

通过 CSS 选择器特异性解决您的问题!

使用 Bootstrap 的“ error”类进行样式设计。可以编写更少的代码。

<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中,类现在是“ has-error”,而不是“ error”。

在 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'的报价: 花了一段时间才发现..。

另一个解决方案: 创建根据子输入切换 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);
});
}
}
}
};
}]);

谢谢@farincz 给出了一个很好的答案。下面是我为了适应我的用例而做的一些修改。

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

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

我做了一些修改:

  • 添加了一个检查,以便在表单字段是脏的时候只显示 has 状态,也就是说,直到有人与它们交互时才显示它们。
  • 对于那些不使用 jQuery 的用户,修改了传递到 element.find()的字符串,因为 Angular 的 jQLite 中的 element.find()只支持通过 tagname 查找元素。
  • 增加了对选择框和文本区域的支持。
  • element.find()包装在 $timeout中,以支持元素可能尚未将其子元素呈现到 DOM 的情况(例如,如果元素的子元素用 ng-if标记)。
  • 修改了 if表达式以检查返回数组的长度(@ farincz 的回答if(input)始终返回 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 的 包装盒,它将所有这些捆绑在一起。

对@Andrew Smith 的回答略有改善。 我改变输入元素和使用 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);
});
});
}
});
}
};
}]);

我对 Jason IM 的回答进行了改进,增加了两个新的指令 show-valid- error 和 show-valid- 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-valid- error 可以添加到错误的容器中,以便根据表单字段的有效性显示/隐藏容器。

Show- 验证-错误显示或隐藏基于该表单字段对给定类型的有效性的元素。

预期用途的一个例子:

        <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 您可以添加其他类型的控件,如 select、 date、 password 等

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 : 不需要在控件中添加任何内容,如果需要的话,除了 n- 必需

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

只要尝试和键入一些文本在您的控制,我发现它真的很方便,真棒。

<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 表单验证的人来说,我已经编写了一个非常小的模块,可以在不改变 HTML 或 Javascript 任何形式的情况下实现同样的效果。

检查 自举角度验证

以下是三个简单的步骤:

  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不需要一起工作。

这是基于 jQuery 验证的概念。此模块为验证错误提供一些额外的验证和常见的通用消息。