Uso del complemento JQuery Validate para validar múltiples campos de formulario con nombres idénticos

StackOverflow https://stackoverflow.com/questions/931687

Pregunta

Tengo un formulario generado dinámicamente con campos de entrada con el mismo nombre (por ejemplo:"mapa").No tengo la opción de cambiar los nombres de los campos o generar nombres de campos únicos porque el código del controlador de formulario (Perl/CGI) está diseñado para manejar una matriz de valores de entrada (en este caso @map).

¿Cómo puedo utilizar JQuery? Validar complemento ¿Validar un formulario en tal situación?Específicamente, me gustaría que exactamente un elemento de la matriz enviada tuviera un valor fijo determinado.Actualmente estoy usando un controlador de eventos personalizado que crea un objeto JSON con serializeArray() y luego lo atraviesa para garantizar que se cumpla la condición.Pero como he usado el complemento Validar en el resto de la aplicación, me preguntaba si ese caso se puede manejar usando el mismo complemento aquí también.

Gracias por su atención.

¿Fue útil?

Solución

pasé algún tiempo buscando y probar cosas diferentes cuando finalmente probé la manera más trivial de hacer la validación en múltiples campos. Cada campo y es clones comparten una clase única para cada conjunto. Acabo de bucle a través de las entradas con esa clase y añadí mis reglas de validación como de costumbre. Espero que esto podría ayudar a alguien más.

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





});

Otros consejos

Como no puedo hacer ningún comentario sobre @scampbell respuesta, no sé si sus cerca de puntos de reputación o porque el hilo acaba de cerrar, tengo una contribución a su respuesta,

En lugar de cambiar el archivo de origen jquery.validation puede simplemente reemplazar la función necesita editar sólo en las páginas que lo requiera.

un ejemplo sería:

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

esto podría no ser la mejor solución, pero al menos evita archivos de origen de edición que podría ser reemplazado más tarde, cuando un lanzamiento de nuevas versiones. donde su función overriden podría o no romper

Antiguo sé, pero me encontré con ella en busca de la solución al mismo problema.

Una solución más elegante se ha publicado aquí: http: //web-funda.blogspot .com / 2009/05 / jquery-validación-para-array-de-input.html

Sólo tiene que editar y cambiar el jquery.validate.js checkForm a

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

Me acabo de enterar de un correo electrónico por el autor plugins, Jörn Zaefferer, que requiere la validación de nombres de campo a ser única excepción de los botones de radio y casillas de verificación.

La respuesta de Jason va a hacer el truco, pero yo no quería añadir eventos de clic adicionales en todas las formas que hice esto.

En mi caso, tengo el plugin de validación en cuenta los nombres que terminan con '[]' diferentes a pesar de que puedan tener nombres de campos idénticos. Para hacer esto, yo sobreescribí estos dos métodos internos después de jquery.validate.js cargas.

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

Sólo tiene que utilizar un atributo libre de la salida para almacenar el nombre original, entonces simplemente cambiar el nombre con su índice adjunto:

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

}

A continuación, después de configurar el validador:

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

y cuando haya terminado la validación, volverá de este modo:

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

- Esperamos que esto ayude!

Aquí es cómo lo hice. Un poco más fácil que los métodos propuestos previamente:

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

En mi caso tengo un asistente (3 pasos), que resultó ser aún más complejo, ya que no desea validar todos los campos a la vez. Yo, básicamente, colocar los componentes en pestañas y si es válida la primera pestaña, me muevo a la siguiente, hasta que llegue al último, después de que presento todos los datos. Así, el parámetro tab está el elemento pestaña real (que es un div). entonces yo bucle a través de todos los elementos de entrada a los niños a mi cuenta y comprobar a su validez.

Todo lo demás es estándar.


Sólo por completo aquí es el resto del código: cómo presentar la forma que se hace y cómo mi validador se ve así:

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

Y aquí la función de llamada 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.
}

Estoy usando estas reglas de validación (que yo crea en 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
        }
    }
});

Estoy usando "la validación de jQuery plug-in de 1,7".

El problema ¿por múltiples "($): Entrada de" elementos que comparten el mismo nombre no se validan

es el método $ .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;
        });
    },

La condición

Si (this.name en rulesCache || .....

evalúa para los elementos segundo y próximos que comparten el mismo nombre verdadero ....

La solución sería tener la condición:

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

Disculpe, puritanos JS, que (this.id || this.name) no está al 100% ...

Por supuesto, el

rulesCache [this.name] = true;

línea debe ser cambiado apropiadamente también.

Así que el método $ .validator.prototype.elements sería:

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

});

Tal vez me estoy perdiendo el punto, pero como el validador no funciona con varios nombres (lo intenté...¡falló!) Cambié mi formulario para cambiar dinámicamente los nombres, establecer las reglas y luego desarmar los nombres al enviar.

Dos métodos (ignore el material del wlog, simplemente sale a la consola):

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

Al cargar el formulario, y cada vez que agrego dinámicamente otra fila, llamo al método set, p.

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

Esto cambia los nombres para permitir la validación individual.

En el controlador de envío:thingumy después de la validación lo llamo revertir, es decir

revertGeneratedNames(form, ['amounts']);

Lo que vuelve a cambiar los nombres a los originales antes de publicar los datos.

Creo que entendió mal funcionamiento de los formularios HTML. Cada elemento del formulario tiene que tener un nombre único, excepto múltiples casillas de verificación y botones que permiten elegir uno / múltiples opciones para un campo de datos.

En su caso, no sólo la validación de jQuery, sino también una forma de validación del lado del servidor sería un fracaso, porque no puede asignar las entradas a los campos de datos. Supongamos, que desea que el usuario introduzca prename, apellido, dirección de correo-dirección, fax (opcional) y todos sus campos de entrada han name="map"

De allí tendría que recibir estas listas en enviar:

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

Usted ve que es imposible para validar esta forma fiable.

Te recomiendo volver a examinar la documentación de su controlador de formulario Perl o adaptarlo si escribió por su cuenta.

Para mí esto fue resuelto muy fácilmente mediante la desactivación de la depuración

 $("#_form").validate({
    debug:false,
    //debug: true,
    ...
    });

Hay una solución simple:

$(document).ready(function() {
   $(".form").each(function() {
      $(this).validate({
         ...
         ,errorContainer: $(".status_mess",this) // use "this" as reference to that instance of form.
         ...
      });
   });
});
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top