开发者问题收集

对具有多个输入的 .form-group 进行 jQuery 验证

2016-12-30
9380

使用 jQuery Validation 插件,我为我的 Bootstrap form 定义了以下内容:

$(".form-with-validation").validate({
    errorClass: "help-block",
    errorElement: "span",
    highlight: function(element) {
        $(element).closest('.form-group').addClass('has-error');
    },
    unhighlight: function(element) {
        $(element).closest('.form-group').removeClass('has-error');
    }
});

它适用于简单的表单。但是,当 .form-group 包含多个需要验证的输入(内联)时,带有 highlightunhighlight 的部分不起作用:

<div class="form-group">
    <label class="col-md-4 control-label">State &amp; Zip</label>
    <div class="col-md-3">
        <select class="form-control required" name="state">
            ...
        </select>
    </div>
    <div class="col-md-3">
        <input type="text" class="form-control required" name="zip">
    </div>
</div>

问题是,例如,一旦您选择一个状态,输入就会变为有效,并且其 .form-group 父级 会失去 .has-error ,即使 兄弟输入 (即 zip) 仍然无效 (即在其下方有一个 .help-block 跨度):

在此处输入图像描述

因此,我将 unhighlight 部分更改为以下内容:

unhighlight: function(element) {
    var formGroup = $(element).closest('.form-group');
    var formGroupIsValid = true;
    formGroup.find('input').each(function(){
        if (! $(this).valid())
            formGroupIsValid = false;
    });
    if (formGroupIsValid)
        formGroup.removeClass('has-error');
}

但是我收到以下错误:

Uncaught RangeError: Maximum call stack size exceeded

有什么想法吗?我尝试了很多方法,但每次都得到相同的错误。

编辑

如果可能的话,我更愿意坚持使用 div.form-group 具有 .has-error 类(因为样式)。

编辑 2

Jsfiddle 来演示该问题。

3个回答

这是我最终得到的解决方案。它比我想象的要简单。正如人们之前指出的那样,任何 form-group 一次都应只包含一个 form-control 。因此,最简单的解决方案是将第二个 form-group 放入第一个 form-group 中,然后将第二个 form-control 放入其中:

<div class="form-group">
    <label class="col-md-4 control-label">State &amp; Zip</label>
    <div class="col-md-6">
        <div class="row">
            <div class="col-sm-6">
                <select class="form-control required" name="state">
                    ...
                </select>
            </div>
            <div class="col-sm-6 form-group" style="margin-bottom:0;padding-right:0">
                <input type="text" class="form-control required" name="zip">
            </div>
        </div>
    </div>
</div>

只需几个 CSS 样式,就可以完美运行并且看起来不错。这是一个 jsfiddle

Alex
2017-01-04

您正在调用一个函数,而该函数又调用另一个函数,依此类推,直到达到调用堆栈限制。我假设问题出在您调用 .valid() 时的 .each 循环中。

不过,您不必做任何这些。您不应该定位 form-group ,而应该专门定位输入周围的某个内容,这样您就不必更改 unhightlight 函数。例如:

<div class="form-group">
    <label class="col-md-4 control-label">State &amp; Zip</label>
    <div class="col-md-3 inputToValidate">
        <select class="form-control required" name="state">
            ...
        </select>
    </div>
    <div class="col-md-3 inputToValidate">
        <input type="text" class="form-control required" name="zip">
    </div>
</div>

然后将 JavaScript 代码更新为:

$(".form-with-validation").validate({
    errorClass: "help-block",
    errorElement: "span",
    highlight: function(element) {
        $(element).closest('.inputToValidate').addClass('has-error');
    },
    unhighlight: function(element) {
        $(element).closest('.inputToValidate').removeClass('has-error');
    }
});
Eric G
2016-12-30

I'd prefer to stick with div.form-group having .has-error class if possible

使用插件提供的选项无法实现。有效/无效类在被验证的元素上切换。 highlightunhighlight 函数可以修改为使用 jQuery DOM 遍历等切换其他元素上的类。

但是,当父容器的任何子元素无效时,您需要使父容器“无效”的逻辑……插件没有配备此功能。一旦无效子元素触发父元素上的错误类,任何有效子元素都会将有效类应用于同一父元素。

一种解决方法是使用 外部 keyupchange 处理程序,该处理程序查看所有同级输入元素上的类并相应地切换其父类。根据您自己的代码,未经测试...

$('input, select').on('keyup change', function() {
    var formGroup = $(this).closest('.form-group');
    var formGroupIsValid = true;
    formGroup.find('input, select').each(function(){
        if (! $(this).valid()) {
            formGroupIsValid = false;
        }
    });
    if (formGroupIsValid) {
        formGroup.removeClass('has-error');
    } else {
        formGroup.addClass('has-error');
    }
});

I get the following error: Uncaught RangeError: Maximum call stack size exceeded .... Any ideas why?

是的,您正在从 .validate() 方法中调用 .valid() 方法(通过 unhighlight )。因此,从此方法中调用 $(this).valid() 只会导致再次调用 unhighlight ... 如此反复。

Sparky
2016-12-30