使用 JQuery Validate Plugin 验证多个具有相同名称的表单字段

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/931687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 10:09:33  来源:igfitidea点击:

Using JQuery Validate Plugin to validate multiple form fields with identical names

jqueryvalidationjquery-validate

提问by Ya. Perelman

I have a dynamically generated form with input fields with the same name (for example: "map"). I do not have the option of changing the field names or generating unique field names because the form handler code (Perl/CGI) is designed to handle an array of input values (in this case @map).

我有一个动态生成的表单,其中输入字段具有相同的名称(例如:“地图”)。我没有更改字段名称或生成唯一字段名称的选项,因为表单处理程序代码 (Perl/CGI) 旨在处理输入值数组(在本例中为@map)。

How can I use the JQuery Validate Pluginto validate a form in such a situation? Specifically I would want exactly one element of the submitted array to have a certain fixed value. I am currently using a custom event handler that creates a JSON object with serializeArray()and then traverses it to ensure that the condition is met. But since I have used the Validate Plugin in the rest of the application, I was wondering if such a case may be handled using the same plugin here too.

在这种情况下,如何使用 JQuery验证插件来验证表单?具体来说,我希望提交的数组中只有一个元素具有某个固定值。我目前正在使用一个自定义事件处理程序,它创建一个 JSON 对象,serializeArray()然后遍历它以确保满足条件。但是由于我在应用程序的其余部分使用了验证插件,我想知道是否可以在这里使用相同的插件处理这种情况。

Thank you for your attention.

感谢您的关注。

采纳答案by Ya. Perelman

I spent some time searching and trying different things when finally I tried the most trivial way of doing validation on multiple fields. Each field and it's clones share a class unique to each set. I just looped through the inputs with that class and added my validation rules as usual. I hope this might help someone else.

我花了一些时间搜索和尝试不同的东西,最后我尝试了对多个字段进行验证的最简单的方法。每个字段及其克隆共享每个集合独有的类。我只是用那个类循环输入,并像往常一样添加了我的验证规则。我希望这可以帮助别人。

    $("#submit").click(function(){
    $("input.years").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify the years you worked"
            }
        } );            
    });

    $("input.employerName").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify the employer name"
            }
        } );            
    }); 

    $("input.employerPhone").each(function(){
        $(this).rules("add", {
            required: true,
            minlength: 10,
            messages: {
                required: "Specify the employer phone number",
                minlength: "Not long enough"
            }
        } );            
    }); 

    $("input.position").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify your position"
            }
        } );            
    });             

    $("input.referenceName").each(function(){
        $(this).rules("add", {
            required: true,
            messages: {
                required: "Specify the reference name"
            }
        } );            
    });         

    $("input.referencePhone").each(function(){
        $(this).rules("add", {
            required: true,
            minlength: 10,
            messages: {
                required: "Specify your reference phone number",
                minlength: "Not long enough"
            }
        } );            
    });

// Now do your normal validation here, but don't assign rules/messages for the fields we just set them for





});

回答by Ahmed Galal

As i cant comment on @scampbell answer, i dunno if its about reputation points or because the thread has just closed, i have a contribution to his answer,

由于我无法对@scampbell 的回答发表评论,我不知道是关于声誉点还是因为该线程刚刚关闭,我对他的回答有所贡献,

Instead of changing the source file jquery.validation you can simply override the function you need to edit only in the pages that requires it.

无需更改源文件 jquery.validation,您只需覆盖仅在需要它的页面中需要编辑的函数。

an example would be:

一个例子是:

$.validator.prototype.checkForm = function() {
    //overriden in a specific page
    this.prepareForm();
    for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++) {
        if (this.findByName(elements[i].name).length !== undefined && this.findByName(elements[i].name).length > 1) {
            for (var cnt = 0; cnt < this.findByName(elements[i].name).length; cnt++) {
                this.check(this.findByName(elements[i].name)[cnt]);
            }
        } else {
            this.check(elements[i]);
        }
    }
    return this.valid();
};

this might not be the best solution, but at least it avoids editing source files that could be replaced later when a new version releases. where your overriden function might or might not break

这可能不是最好的解决方案,但至少它避免了编辑可以在新版本发布时替换的源文件。您的覆盖功能可能会或可能不会中断

回答by scampbell

Old thread I know but I came across it in search of the fix to the same problem.

我知道旧线程,但我在寻找相同问题的修复程序时遇到了它。

A more elegant solution has been posted here: http://web-funda.blogspot.com/2009/05/jquery-validation-for-array-of-input.html

这里发布了一个更优雅的解决方案:http: //web-funda.blogspot.com/2009/05/jquery-validation-for-array-of-input.html

You simply edit jquery.validate.js and change the checkForm to

您只需编辑 jquery.validate.js 并将 checkForm 更改为

    checkForm: function() {
    this.prepareForm();
    for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
        if (this.findByName( elements[i].name ).length != undefined && this.findByName( elements[i].name ).length > 1) {
            for (var cnt = 0; cnt < this.findByName( elements[i].name ).length; cnt++) {
                    this.check( this.findByName( elements[i].name )[cnt] );
            }
        } else {
            this.check( elements[i] );
        }
    }
    return this.valid();
}

回答by Ya. Perelman

I just learned from a mail by the Plugins author, J?rn Zaefferer, that validation requires field names to be unique except for radio buttons and check boxes.

我刚刚从插件作者 J?rn Zaefferer 的一封邮件中了解到,除了单选按钮和复选框之外,验证要求字段名称是唯一的。

回答by Steve Farthing

Jason's answer will do the trick, but I didn't want to add extra click events on every form I did this on.

Jason 的回答可以解决问题,但我不想在我执行此操作的每个表单上添加额外的点击事件。

In my case, I have the validation plugin consider names ending with '[]' different even though they may have identical fieldnames. To do this, I overwrote these two internal methods after jquery.validate.js loads.

就我而言,我让验证插件考虑以 '[]' 结尾的名称不同,即使它们可能具有相同的字段名。为此,我在 jquery.validate.js 加载后重写了这两个内部方法。

$.validator.prototype.elements= function() {
var validator = this,
    rulesCache = {};

// select all valid inputs inside the form (no submit or reset buttons)
// workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
return $([]).add(this.currentForm.elements)
.filter(":input")
.not(":submit, :reset, :image, [disabled]")
.not( this.settings.ignore )
.filter(function() {
    !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);

    // select only the first element for each name (EXCEPT elements that end in []), and only those with rules specified
    if ( (!this.name.match(/\[\]/gi) && this.name in rulesCache) || !validator.objectLength($(this).rules()) )
        return false;

    rulesCache[this.name] = true;
    return true;
});
};


$.validator.prototype.idOrName = function(element) {

// Special edit to get fields that end with [], since there are several [] we want to disambiguate them
// Make an id on the fly if the element doesnt have one
if(element.name.match(/\[\]/gi)) {
    if(element.id){
        return element.id;
    } else {
        var unique_id = new Date().getTime();

        element.id = new Date().getTime();

        return element.id;
    }
}

return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
};

回答by Matt Kircher

Simply use an unused attribute of the input to store the original name, then just rename with it's index attached:

只需使用输入的未使用属性来存储原始名称,然后只需重命名并附加索引:

function addMultiInputNamingRules(form, field, rules){    
    $(form).find(field).each(function(index){
    $(this).attr('alt', $(this).attr('name'));
    $(this).attr('name', $(this).attr('name')+'-'+index);
    $(this).rules('add', rules);
});

}

}

function removeMultiInputNamingRules(form, field){    
    $(form).find(field).each(function(index){
    $(this).attr('name', $(this).attr('alt'));
    $(this).removeAttr('alt');
});

}

}

Then after you set your validator:

然后在设置验证器之后:

addMultiInputNamingRules('#form-id', 'input[name="multifield[]"]', { required:true });

and when you've finished validating, revert back like so:

当你完成验证后,像这样恢复:

removeMultiInputNamingRules('#form-id', 'input[alt="multifield[]"]');

-- Hope this helps!

- 希望这可以帮助!

回答by Stef

Here is how I did it. A bit easier than previously proposed methods:

这是我如何做到的。比以前提出的方法更容易一些:

function validateTab(tab) {
    var valid = true;
    $(tab).find('input').each(function (index, elem) {
        var isElemValid = $("#registrationForm").validate().element(elem);
        if (isElemValid != null) { //this covers elements that have no validation rule
            valid = valid & isElemValid;
        }
    });

    return valid;
}

In my case I have a wizard (of 3 steps) which turned out to be even more complex as I don't want to validate all fields at once. I basically place components in tabs and if first tab is valid, I move to the next, until I get to last one, after which I submit all data. Thus the tabparameter there is the actual tab element (which is a div). I then loop through all input elements children to my tab and check them for validity.

就我而言,我有一个向导(3 个步骤),结果证明它更加复杂,因为我不想一次验证所有字段。我基本上将组件放在选项卡中,如果第一个选项卡有效,我将移至下一个,直到最后一个,然后提交所有数据。因此,tab那里的参数是实际的选项卡元素(即 a div)。然后我将所有输入元素的子元素循环到我的选项卡并检查它们的有效性。

Everything else is standard.

其他一切都是标准的。



Just for completeness here is the rest of the code: how the form submit is done and how my validator looks like:

为了完整起见,这里是其余的代码:表单提交是如何完成的以及我的验证器的样子:

<a href="javascript:moveToNextTab(1)" class="button next">Submit</a>

And here the js function called:

这里调用了 js 函数:

function moveToNextTab(currentTab) {
    var tabs = document.getElementsByClassName("tab");
    //loop through tabs and validate the current one.
    //If valid, hide current tab and make next one visible.
}

I'm using these validation rules (which I create on JQuery.ready):

我正在使用这些验证规则(我在 JQuery.ready 上创建的):

$("#registrationForm").validate({
    rules: {
        birthdate: {
            required: true,
            date: true
        },
        name: "required",
        surname: "required",
        address: "required",
        postalCode: "required",
        city: "required",
        country: "required",
        email: {
            required: true,
            email: true
        }
    }
});

回答by Motlicek Petr

I'm using "jQuery validation plug-in 1.7".

我正在使用“jQuery 验证插件 1.7”。

The problem why multiple "$(:input)" elements sharing the same name are not validated

多个“$(:input)”同名元素未验证的问题

is the $.validator.element method:

是 $.validator.element 方法:

elements: function() {
        var validator = this,
            rulesCache = {};

        // select all valid inputs inside the form (no submit or reset buttons)
        // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
        return $([]).add(this.currentForm.elements)
        .filter(":input")
        .not(":submit, :reset, :image, [disabled]")
        .not( this.settings.ignore )
        .filter(function() {
            !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);

            // select only the first element for each name, and only those with rules specified
            if ( this.name in rulesCache || !validator.objectLength($(this).rules()) )
                return false;

            rulesCache[this.name] = true;
            return true;
        });
    },

The condition

条件

if ( this.name in rulesCache ||.....

if ( rulesCache 中的 this.name ||.....

evaluates for the second and next elements sharing the same name true....

评估共享相同名称的第二个和下一个元素 true....

The solution would be having the condition:

解决方案将具有以下条件:

(this.id || this.name) in rulesCache

(this.id || this.name) 在 rulesCache

Excuse me, JS puritans, that (this.id || this.name) is not at 100%...

对不起,JS 清教徒,那个 (this.id || this.name) 不是 100%...

Of course, the

当然,该

rulesCache[this.name] = true;

rulesCache[this.name] = true;

line must be changed appropriately as well.

线也必须适当改变。

So the $.validator.prototype.elements method would be:

所以 $.validator.prototype.elements 方法是:

$(function () {
if ($.validator) {
    //fix: when several input elements shares the same name, but has different id-ies....
    $.validator.prototype.elements = function () {

        var validator = this,
            rulesCache = {};

        // select all valid inputs inside the form (no submit or reset buttons)
        // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
        return $([]).add(this.currentForm.elements)
        .filter(":input")
        .not(":submit, :reset, :image, [disabled]")
        .not(this.settings.ignore)
        .filter(function () {
            var elementIdentification = this.id || this.name;

            !elementIdentification && validator.settings.debug && window.console && console.error("%o has no id nor name assigned", this);

            // select only the first element for each name, and only those with rules specified
            if (elementIdentification in rulesCache || !validator.objectLength($(this).rules()))
                return false;

            rulesCache[elementIdentification] = true;
            return true;
        });
    };
}

});

});

回答by Alfonzo

Maybe I'm missing the point, but since the validator doesn't work with multiple names (tried... failed!) I changed my form to dynamically change the names, set the rules, then unset the names on submit.

也许我错过了这一点,但由于验证器不能处理多个名称(尝试...失败!)我更改了表单以动态更改名称,设置规则,然后在提交时取消设置名称。

Two methods (ignore the wlog stuff, it just outputs to the console):

两种方法(忽略 wlog 的东西,它只是输出到控制台):

// convert the field names into generated ones to allow fields with the same names 
// to be validated individually. The original names are stored as data against the
// elements, ready to be replaced. The name is replaced with
// "multivalidate-<name>-<id>", e.g. original => 'multivalidate-original-1'

function setGeneratedNamesWithValidationRules(form, fields, rules) {

    var length = fields.length;

    for (var i=0; i < length; ++i ){
        var name = fields[i];

        var idCounter = 0;  
        // we match either the already converted generator names or the original
        $("form [name^='multivalidate-" + name + "'], form [name='" + name + "']").each(function() {
            // identify the real name, either from the stored value, or the actual name attribute
            var realName = $(this).data('realName');
            if (realName == undefined) {
                realName = $(this).attr("name");
                $(this).data('realName', realName);
            }

            wlog("Name: " + realName + " (actual: " + $(this).attr("name") + "), val: " + $(this).val() + ". Rules: " + rules[realName]);
            $(this).attr("name", "multivalidate-" + realName + "-" + idCounter);
            if (rules[realName]) {
                $(this).rules("add", rules[realName]);
            }
            idCounter++;
        });
    }
}

function revertGeneratedNames(form, fields) {

    var length = fields.length;

    for (var i=0; i < length; ++i ){
        var name = fields[i];
        wlog("look for fields names [" + name + "]");

        $("form [name^='multivalidate-" + name + "']").each(function() {
            var realName = $(this).data('realName');
            if (realName == undefined) {
                wlog("Error: field named [" + $(this).attr("name") + "] does not have a stored real name");
            } else {
                wlog("Convert [" + $(this).attr("name") + "] back to [" + realName + "]");
                $(this).attr("name", realName);
            }
        });
    }
}

On the form load, and whenever I dynamically add another row, I call the set method, e.g.

在表单加载时,每当我动态添加另一行时,我都会调用 set 方法,例如

setGeneratedNamesWithValidationRules($("#my-dynamic-form"), ['amounts'], { 'amounts': 'required'} );

This changes the names to allow individual validation.

这会更改名称以允许单独验证。

In the submitHandler: thingumy after validation I call the revert, i.e.

在 submitHandler: thingumy 验证后我调用还原,即

revertGeneratedNames(form, ['amounts']);

Which switches the names back to the originals before posting the data.

在发布数据之前将名称切换回原始名称。

回答by Franz

I think you misunderstood the workings of HTML forms. Every form element needs to have an unique name, except multiple checkboxes and buttons that allow you to choose one/multiple options for one data field.

我认为您误解了 HTML 表单的工作原理。除了允许您为一个数据字段选择一个/多个选项的多个复选框和按钮之外,每个表单元素都需要有一个唯一的名称。

In your case, not only JQuery validation, but also a server-side form validator would fail, because it can't assign the inputs to the data fields. Suppose, you want the user to enter prename, lastname, e-mail-adress, fax (optional) and all your input fields have name="map"

在您的情况下,不仅 JQuery 验证,而且服务器端表单验证器都会失败,因为它无法将输入分配给数据字段。假设,您希望用户输入姓名、姓氏、电子邮件地址、传真(可选)并且您的所有输入字段都有name="map"

Then you would receive these lists on submit:

然后你会在提交时收到这些列表:

map = ['Joe','Doe','joe.doeAThotmail.com','++22 20182238'] //All fields completed
map = ['Joe','Doe','joe.doeAThotmail.com'] //OK, all mandatory fields completed 
map = ['Doe', 'joe.doeAThotmail.com','++22 20182238']//user forgot prename, should yield error

You see that it is impossible to validate this form reliably.

您会看到无法可靠地验证此表单。

I recommend to revisit the documentation of your perl form handler or adapt it if you wrote it on your own.

我建议重新访问您的 perl 表单处理程序的文档,或者如果您自己编写它,则对其进行调整。