Utilizzo di JQuery Validate Plugin per convalidare più campi modulo con nomi identici

Ho un modulo generato dynamicmente con campi di input con lo stesso nome (ad esempio: “mappa”). Non ho la possibilità di modificare i nomi dei campi o di generare nomi di campi univoci perché il codice del gestore di moduli (Perl / CGI) è progettato per gestire una matrice di valori di input (in questo caso @map ).

Come posso utilizzare il plugin di convalida JQuery per convalidare un modulo in tale situazione? Nello specifico vorrei che esattamente un elemento dell’array inviato abbia un determinato valore fisso. Attualmente sto usando un gestore di eventi personalizzato che crea un object JSON con serializeArray() e poi lo attraversa per garantire che la condizione sia soddisfatta. Ma dal momento che ho usato il plugin Validate nel resto dell’applicazione, mi chiedevo se un caso del genere potesse essere gestito usando lo stesso plugin anche qui.

Grazie per l’attenzione.

Ho passato un po ‘di tempo a cercare e provare cose diverse quando finalmente ho provato il più semplice modo di fare convalida su più campi. Ogni campo e i suoi cloni condividono una class unica per ogni set. Ho semplicemente fatto il giro degli input con quella class e ho aggiunto le mie regole di validazione come al solito. Spero che questo possa aiutare qualcun altro.

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

Vecchio filo che conosco ma l’ho incontrato cercando la soluzione allo stesso problema.

Una soluzione più elegante è stata pubblicata qui: http://web-funda.blogspot.com/2009/05/jquery-validation-for-array-of-input.html

È sufficiente modificare jquery.validate.js e modificare il 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(); } 

Poiché non posso commentare la risposta di @scampbell, non so se si tratta di punti di reputazione o perché il thread è appena chiuso, ho un contributo alla sua risposta,

Invece di modificare il file sorgente jquery.validation, puoi semplicemente sovrascrivere la funzione che devi modificare solo nelle pagine che lo richiedono.

un esempio potrebbe essere:

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

questa potrebbe non essere la soluzione migliore, ma almeno evita di modificare i file di origine che potrebbero essere sostituiti in seguito quando verrà rilasciata una nuova versione. dove la tua funzione di overriden potrebbe o non potrebbe rompere

Ho appena saputo da una mail dell’autore dei plugin, Jörn Zaefferer, che la convalida richiede che i nomi dei campi siano univoci tranne che per i pulsanti di opzione e le caselle di controllo.

La risposta di Jason farà il trucco, ma non volevo aggiungere eventi di clic in più su ogni modulo su cui l’ho fatto.

Nel mio caso, il plugin di convalida considera i nomi che terminano con “[]” diversi anche se possono avere nomi di campo identici. Per fare ciò, ho sovrascritto questi due metodi interni dopo il caricamento di 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); }; 

Usa semplicemente un attributo inutilizzato dell’input per memorizzare il nome originale, quindi rinomina semplicemente con il suo indice allegato:

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

}

Quindi dopo aver impostato il tuo validatore:

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

e quando hai finito di convalidare, torna indietro in questo modo:

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

— Spero che questo ti aiuti!

Ecco come l’ho fatto. Un po ‘più semplice dei metodi proposti in precedenza:

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

Nel mio caso ho un wizard (di 3 passi) che risulta essere ancora più complesso in quanto non voglio convalidare tutti i campi contemporaneamente. Fondamentalmente posiziono i componenti nelle tabs e se la prima scheda è valida, passo al successivo, fino a quando non riesco a durarne una, dopodiché invio tutti i dati. Quindi il parametro tab contiene l’elemento tab effettivo (che è un div ). Quindi faccio scorrere tutti gli elementi di input secondari nella mia scheda e ne controllo la validità.

Tutto il resto è standard.


Solo per completezza ecco il resto del codice: come viene fatto il modulo di invio e come appare il mio validatore:

  

E qui la funzione js ha chiamato:

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

Sto usando queste regole di convalida (che creo su 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 } } }); 

Sto usando “jQuery validation plug-in 1.7”.

Il problema perché più elementi “$ (: input)” che condividono lo stesso nome non sono convalidati

è il metodo $ .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 condizione

se (this.name in rulesCache || …..

valuta per il secondo e i successivi elementi che condividono lo stesso nome vero ….

La soluzione avrebbe la condizione:

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

Scusami, JS puritani, che (this.id || this.name) non è al 100% …

Certo, il

rulesCache [this.name] = true;

la linea deve essere cambiata in modo appropriato.

Quindi il metodo $ .validator.prototype.elements sarebbe:

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

});

Forse mi manca il punto, ma dal momento che il validatore non funziona con più nomi (provato … fallito!) Ho cambiato il mio modulo per cambiare dynamicmente i nomi, impostare le regole, quindi rimuovere i nomi su submit.

Due metodi (ignora la roba di wlog, si limita alla console):

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

Sul caricamento del modulo e ogni volta che aggiungo dynamicmente un'altra riga, chiamo il metodo set, ad es

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

Questo cambia i nomi per consentire la convalida individuale.

Nel submitHandler: thingumy dopo la convalida chiamo il ripristino, cioè

 revertGeneratedNames(form, ['amounts']); 

Che cambia i nomi agli originali prima di postare i dati.

Penso che tu abbia frainteso il funzionamento dei moduli HTML. Ogni elemento del modulo deve avere un nome univoco, ad eccezione di più checkbox e pulsanti che consentono di scegliere una / più opzioni per un campo di dati.

Nel tuo caso, non solo la validazione di JQuery, ma anche un validatore di moduli sul lato server fallirebbe, perché non può assegnare gli input ai campi di dati. Supponiamo che tu voglia che l’utente inserisca nome, cognome, indirizzo e-mail, fax (opzionale) e tutti i campi di inserimento abbiano name="map"

Quindi riceverai queste liste su 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 

Vedi che è imansible convalidare questo modulo in modo affidabile.

Raccomando di rivisitare la documentazione del tuo gestore di moduli perl o adattarlo se lo hai scritto da solo.

Per me questo è stato risolto molto facilmente disabilitando il debug

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

C’è una soluzione semplice:

 $(document).ready(function() { $(".form").each(function() { $(this).validate({ ... ,errorContainer: $(".status_mess",this) // use "this" as reference to that instance of form. ... }); }); });