Использование JQuery Validate Plugin для проверки нескольких полей формы с одинаковыми именами - PullRequest
47 голосов
/ 31 мая 2009

У меня есть динамически сгенерированная форма с одноименными полями ввода (например: «карта»). У меня нет возможности изменять имена полей или генерировать уникальные имена полей, потому что код обработчика формы (Perl / CGI) предназначен для обработки массива входных значений (в данном случае @map).

Как я могу использовать JQuery Validate Plugin для проверки формы в такой ситуации? В частности, я бы хотел, чтобы ровно один элемент представленного массива имел определенное фиксированное значение. В настоящее время я использую пользовательский обработчик событий, который создает объект JSON с serializeArray(), а затем пересекает его, чтобы убедиться, что условие выполнено. Но так как я использовал плагин Validate в остальной части приложения, мне было интересно, может ли такой случай быть обработан с использованием того же самого плагина и здесь.

Спасибо за внимание.

Ответы [ 12 ]

59 голосов
/ 31 июля 2012

Поскольку я не могу прокомментировать ответ @scampbell, я не знаю, о чем идет речь о репутации или потому что тема только что закрылась, у меня есть вклад в его ответ,

Вместо изменения исходного файла jquery.validation вы можете просто переопределить функцию, которую нужно редактировать, только на тех страницах, где это требуется.

пример будет:

$.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();
};

это может быть не лучшим решением, но, по крайней мере, избегает редактирования исходных файлов, которые могут быть заменены позже, когда выйдет новая версия. где ваша переопределенная функция может или не может сломаться

55 голосов
/ 09 ноября 2010

Старая ветка я знаю, но наткнулся на нее в поисках решения той же проблемы.

Более элегантное решение было размещено здесь: http://web -funda.blogspot.com / 2009/05 / JQuery-проверка-для-массива из-input.html

Вы просто редактируете 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();
}
39 голосов
/ 06 августа 2009

Я потратил некоторое время на поиск и пробу разных вещей, когда, наконец, попробовал самый тривиальный способ проверки на нескольких полях. Каждое поле и его клоны имеют класс, уникальный для каждого набора. Я просто перебрал входные данные с этим классом и добавил свои правила проверки как обычно. Я надеюсь, что это может помочь кому-то еще.

    $("#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





});
11 голосов
/ 01 июня 2009

Я только что узнал из письма от автора плагинов, Йорна Зефферера, что проверка требует, чтобы имена полей были уникальными, за исключением переключателей и флажков.

4 голосов
/ 31 марта 2011

Ответ Джейсона поможет, но я не хотел добавлять дополнительные события кликов в каждую форму, на которой я это сделал.

В моем случае, плагин проверки считает имена, заканчивающиеся на '[]' разными, даже если они могут иметь одинаковые имена полей. Для этого я переписал эти два внутренних метода после загрузки 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);
};
3 голосов
/ 17 января 2012

Вот как я это сделал. Немного проще, чем предложенные ранее методы:

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;
}

В моем случае у меня есть мастер (из 3 шагов), который оказался еще более сложным, так как я не хочу проверять все поля одновременно. Я в основном размещаю компоненты на вкладках, и если первая вкладка действительна, я перехожу к следующей, пока не доберусь до последней, после чего отправляю все данные. Таким образом, параметр tab представляет собой фактический элемент табуляции (который является div). Затем я перебираю все дочерние элементы ввода на своей вкладке и проверяю их на правильность.

Все остальное стандартно.


Просто для полноты приведем остальную часть кода: как выполняется отправка формы и как выглядит мой валидатор:

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

А вот функция 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.
}

Я использую эти правила проверки (которые я создаю на 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
        }
    }
});
3 голосов
/ 20 октября 2010

Просто используйте неиспользуемый атрибут ввода для сохранения исходного имени, а затем просто переименуйте его с прикрепленным индексом:

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');
});

}

Затем после того, как вы установили свой валидатор:

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

и когда вы закончите проверку, вернитесь обратно так:

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

- Надеюсь, это поможет!

2 голосов
/ 28 июня 2011

Я использую «плагин проверки jQuery 1.7».

Проблема, почему несколько элементов "$ (: input)", имеющих одно и то же имя, не проверены

- это метод $ .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;
        });
    },

Состояние

if (this.name в rulesCache || .....

оценивает для второго и следующих элементов, имеющих одинаковое имя, true ....

Решение будет иметь условие:

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

Извините, JS puritans, что (this.id || this.name) не на 100% ...

Конечно,

rulesCache [this.name] = true;

Строка

также должна быть соответствующим образом изменена.

Таким образом, метод $ .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;
        });
    };
}
* * 1 028}); * * тысяча двадцать девять
1 голос
/ 19 октября 2010

Возможно, я упускаю суть, но поскольку валидатор не работает с несколькими именами (попытался ... не получилось!), Я изменил свою форму, чтобы динамически изменить имена, установить правила, а затем сбросить имена при отправке. .

Два метода (игнорируйте материал 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);
            }
        });
    }
}

При загрузке формы и всякий раз, когда я динамически добавляю другую строку, я вызываю метод set, например,

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

Это меняет имена, чтобы разрешить индивидуальную проверку.

В submitHandler: штуковину после проверки я называю возвратом, т.е.

revertGeneratedNames(form, ['amounts']);

Что переключает имена обратно на оригиналы перед публикацией данных.

0 голосов
/ 05 апреля 2015

Для меня это было решено очень легко путем отключения отладки

 $("#_form").validate({
    debug:false,
    //debug: true,
    ...
    });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...