Estou usando o excelente jQuery Validate Plugin para validar alguns formulários. Em um formulário, preciso garantir que o usuário preencha pelo menos um de um grupo de campos. Acho que tenho uma solução muito boa e gostaria de compartilhá-la. Por favor, sugira quaisquer melhorias que você possa imaginar.
Não encontrando uma maneira integrada de fazer isso, pesquisei e encontrei o método de validação personalizado de Rebecca Murphey , que foi muito útil.
Eu melhorei isso de três maneiras:
- Para permitir que você passe um seletor para o grupo de campos
- Para permitir que você especifique quantos desse grupo devem ser preenchidos para a validação passar
- Para mostrar todas as entradas no grupo como aprovadas na validação assim que uma delas passar na validação. (Veja a mensagem para Nick Craver no final.)
Portanto, você pode dizer "pelo menos X entradas que correspondem ao seletor Y devem ser preenchidas."
O resultado final, com marcação como esta:
<input class="productinfo" name="partnumber">
<input class="productinfo" name="description">
... é um grupo de regras como este:
// Both these inputs input will validate if
// at least 1 input with class 'productinfo' is filled
partnumber: {
require_from_group: [1,".productinfo"]
}
description: {
require_from_group: [1,".productinfo"]
}
O item nº 3 assume que você está adicionando uma classe de .checked
às suas mensagens de erro após a validação bem-sucedida. Você pode fazer isso da seguinte maneira, conforme demonstrado aqui .
success: function(label) {
label.html(" ").addClass("checked");
}
Como na demonstração vinculada acima, eu uso CSS para dar a cada span.error
um uma imagem X como plano de fundo, a menos que ele tenha a classe .checked
, caso em que recebe uma imagem de marca de seleção.
Este é meu código até agora:
jQuery.validator.addMethod("require_from_group", function(value, element, options) {
var numberRequired = options[0];
var selector = options[1];
//Look for our selector within the parent form
var validOrNot = $(selector, element.form).filter(function() {
// Each field is kept if it has a value
return $(this).val();
// Set to true if there are enough, else to false
}).length >= numberRequired;
// The elegent part - this element needs to check the others that match the
// selector, but we don't want to set off a feedback loop where each element
// has to check each other element. It would be like:
// Element 1: "I might be valid if you're valid. Are you?"
// Element 2: "Let's see. I might be valid if YOU'RE valid. Are you?"
// Element 1: "Let's see. I might be valid if YOU'RE valid. Are you?"
// ...etc, until we get a "too much recursion" error.
//
// So instead we
// 1) Flag all matching elements as 'currently being validated'
// using jQuery's .data()
// 2) Re-run validation on each of them. Since the others are now
// flagged as being in the process, they will skip this section,
// and therefore won't turn around and validate everything else
// 3) Once that's done, we remove the 'currently being validated' flag
// from all the elements
if(!$(element).data('being_validated')) {
var fields = $(selector, element.form);
fields.data('being_validated', true);
// .valid() means "validate using all applicable rules" (which
// includes this one)
fields.valid();
fields.data('being_validated', false);
}
return validOrNot;
// {0} below is the 0th item in the options field
}, jQuery.format("Please fill out at least {0} of these fields."));
Hooray!
Gritar
Agora, para essa mensagem - originalmente, meu código apenas ocultou cegamente as mensagens de erro nos outros campos correspondentes em vez de revalidá-los, o que significava que se houvesse outro problema (como 'apenas números são permitidos e você inseriu letras') , ficou oculto até que o usuário tentou enviar. Isso porque eu não sabia como evitar o ciclo de feedback mencionado nos comentários acima. Eu sabia que devia haver um caminho, então fiz uma pergunta e Nick Craver me esclareceu. Obrigado, Nick!
Questão Resolvida
Originalmente, esse era um tipo de pergunta "deixe-me compartilhar isso e ver se alguém pode sugerir melhorias". Embora eu ainda receba feedback, acho que está bem completo neste ponto. (Pode ser mais curto, mas quero que seja fácil de ler e não necessariamente conciso.) Então, divirta-se!
Atualização - agora parte da validação jQuery
Isso foi adicionado oficialmente à validação do jQuery em 03/04/2012.
fonte
Respostas:
Essa é uma excelente solução, Nathan. Muito obrigado.
Esta é uma maneira de fazer o código acima funcionar, caso alguém tenha problemas para integrá-lo, como eu:
Código dentro do arquivo additional-methods.js :
Código dentro do arquivo html :
Não se esqueça de incluir o arquivo additional-methods.js!
fonte
require_from_group: [1,".partnumber"]
e...[1,".contactname"]
garantir que você está validando as coisas certas.Ótima solução. No entanto, tive o problema de outras regras obrigatórias não funcionarem. Executar .valid () no formulário corrigiu esse problema para mim.
fonte
validator.formSubmit = true
. No método require-from-group, eu verifico esse sinalizador; se está lá eu faço$(element.form).valid();
, caso contrário, eu façofields.valid();
.Obrigado, sean. Isso corrigiu o problema que eu tinha com o código ignorando outras regras.
Também fiz algumas alterações para que a mensagem 'Preencha pelo menos 1 campo ...' seja exibida em um div separado em vez de todos os campos.
colocar no formulário validar o script
adicione isso em algum lugar da página
adicionar ao método require_from_group função addMethod
fonte
Eu enviei um patch que não apresenta os problemas da versão atual (por meio do qual a opção "obrigatório" para de funcionar corretamente em outros campos, uma discussão sobre os problemas com a versão atual está no github .
Exemplo em http://jsfiddle.net/f887W/10/
fonte
Iniciar um nome de variável com $ é necessário em PHP, mas muito estranho (IMHO) em Javascript. Além disso, acredito que você se refere a ele como "$ módulo" duas vezes e "módulo" uma vez, certo? Parece que esse código não deveria funcionar.
Além disso, não tenho certeza se é a sintaxe normal do plugin jQuery, mas posso adicionar comentários acima de sua chamada addMethod, explicando o que você realiza. Mesmo com sua descrição de texto acima, é difícil seguir o código, porque não estou familiarizado com a que fieldset, :illed, value, element ou selector se referem. Talvez a maior parte disso seja óbvio para alguém familiarizado com o plug-in Validate, portanto, use seu julgamento sobre qual é a quantidade certa de explicação.
Talvez você possa separar alguns vars para autodocumentar o código; gostar,
(presumindo que eu entendi o significado desses pedaços de seu código! :))
Não tenho certeza do que "módulo" significa, na verdade - há um nome mais específico que você poderia dar a essa variável?
Bom código, no geral!
fonte
Como o formulário em que estou trabalhando tem várias regiões clonadas com entradas agrupadas como essas, passei um argumento extra para o construtor require_from_group, alterando exatamente uma linha de sua função addMethod:
e desta forma um seletor, ID ou nome de elemento pode ser passado uma vez:
e o validador restringirá a validação aos elementos com aquela classe apenas dentro de cada fieldset, em vez de tentar contar todos os elementos classificados .reqgrp no formulário.
fonte
Aqui está minha chance de responder a Rocket Hazmat, tentando resolver o problema de outros campos definidos que também precisam ser validados, mas marcando todos os campos como válidos no preenchimento bem-sucedido de um.
O único problema restante com isso agora é o caso extremo em que o campo está vazio, depois preenchido e, em seguida, vazio novamente ... nesse caso, o erro será aplicado ao único campo, não ao grupo. Mas isso parece tão improvável de acontecer com qualquer frequência e ainda funciona tecnicamente nesse caso.
fonte
Eu estava tendo problemas com outras regras que não estavam sendo verificadas em conjunto com isso, então mudei:
Para isso:
Também fiz algumas melhorias (pessoais) e esta é a versão que estou usando:
fonte
Obrigado, Nathan. Você me economizou muito tempo.
No entanto, devo notar que esta regra não está pronta para jQuery.noConflict (). Então, deve-se substituir todo $ por jQuery para trabalhar, digamos,
var $j = jQuery.noConflict()
E eu tenho uma pergunta: como eu faria isso se comportar como uma regra embutida? Por exemplo, se eu inserir o e-mail, a mensagem "Insira um e-mail válido" desaparece automaticamente, mas se eu preencher um dos campos do grupo, a mensagem de erro permanece.
fonte