98 votes

jQuery Validate - nécessite qu'au moins un champ d'un groupe soit rempli

Je suis l'aide de l'excellent jQuery Valider Plugin pour valider certaines formes. Sur un formulaire, j'ai besoin de s'assurer que l'utilisateur remplit au moins l'un d'un groupe de champs. Je pense que j'ai une assez bonne solution, et je voulais le partager. Veuillez suggérer d'éventuelles améliorations que vous pouvez penser.

Ne trouvant pas de moyen intégré pour ce faire, j'ai cherché et trouvé Rebecca Murphey personnalisée de la méthode de validation, qui a été très utile.

J'ai amélioré ce, de trois façons:

  1. Pour vous permettre de passer un sélecteur pour le groupe de champs
  2. Pour vous permettre de spécifier combien de ce groupe doivent être remplis pour que la validation de passer
  3. Pour afficher toutes les entrées dans le groupe en tant que passage de validation dès que l'un d'entre eux passe la validation. (Voir shout-out à Nick Craver à la fin.)

Ainsi, vous pouvez dire "au moins X entrées qui correspondent sélecteur de Y doit être rempli."

Le résultat final, avec des balises comme ceci:

<input class="productinfo" name="partnumber">
<input class="productinfo" name="description">

...est un ensemble de règles comme ceci:

// 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"]
}

Élément #3 suppose que vous êtes en train d'ajouter une classe d' .checked pour vos messages d'erreur lors de la validation. Vous pouvez le faire comme suit, comme démontré ici.

success: function(label) {  
        label.html(" ").addClass("checked"); 
}

Comme dans la démo ci-dessus, j'utilise le CSS pour donner à chaque span.error X image comme arrière-plan, à moins qu'il a la classe .checked, auquel cas il devient une marque de contrôle de l'image.

Voici mon code pour l'instant:

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."));

Hourra!

Shout out

Maintenant, pour que shout-out à l'origine, mon code juste aveuglément caché les messages d'erreur sur les autres champs correspondants au lieu de re-valider, ce qui signifie que s'il y avait un autre problème (comme seuls les chiffres sont autorisés et que vous avez entré lettres"), il a caché jusqu'à ce que l'utilisateur a essayé de se soumettre. Ce était parce que je ne sais pas comment faire pour éviter la boucle de rétroaction mentionné dans les commentaires ci-dessus. Je savais qu'il y doit y avoir un moyen, donc j'ai posé une question, et Nick Craver m'a éclairé. Merci, Nick!

Question Résolu

C'était à l'origine un "permettez-moi de partager cela et voir si quelqu'un peut suggérer des améliorations" genre de question. Alors que j'avais toujours les bienvenus commentaires, je pense qu'il est assez complète à ce point. (Il pourrait être plus court, mais je veux qu'il soit facile à lire et pas nécessairement concis.) Donc, juste profiter!

Mise à jour - qui fait maintenant partie de jQuery de Validation

Cela a été officiellement ajouté à jQuery de Validation sur 4/3/2012.

6voto

seanlinmt Points 3032

Belle solution. Cependant, le problème des autres règles obligatoires ne fonctionnait pas. L'exécution de .valid () sur le formulaire a corrigé ce problème pour moi.

 if(!$(element).data('being_validated')) {
  var fields = $(selector, element.form);
  fields.data('being_validated', true); 
  $(element.form).valid();
  fields.data('being_validated', false);
}
 

4voto

Walter Kelly Points 1

Merci Sean. Cela a résolu le problème que j'avais avec le code en ignorant les autres règles.

J'ai également apporté quelques modifications pour que le message "Veuillez remplir au moins un champ .." s'affiche dans un div séparé au lieu de chaque champ.

mettre en forme valider le script

 showErrors: function(errorMap, errorList){
            $("#form_error").html("Please fill out at least 1 field before submitting.");
            this.defaultShowErrors();
        },
 

ajoutez ceci quelque part dans la page

 <div class="error" id="form_error"></div>
 

ajouter à la méthode require_from_group, fonction addMethod

  if(validOrNot){
    $("#form_error").hide();
}else{
    $("#form_error").show();
}
......
}, jQuery.format(" &nbsp;(!)"));
 

3voto

Michael Gundlach Points 10029

Partir d'un nom de variable avec $ est requis en PHP, mais assez bizarre (à mon humble avis) en Javascript. Aussi, je crois que vous faites référence à "$module" deux fois et "module" une fois, non? Il semble que ce code ne fonctionnerait pas.

Aussi, je ne sais pas si c'est normal plugin jQuery de syntaxe, mais je pourrais ajouter des commentaires au-dessus de votre addMethod appel, en expliquant ce que vous accomplissez. Même avec votre texte de description ci-dessus, il est difficile de suivre le code, parce que je ne suis pas familier avec ce jeu de champs, :rempli, la valeur de l'élément, ou le sélecteur de référence. Peut-être les la plupart de ceci est évident pour quelqu'un de familier avec le Valider plugin, utilisez donc un jugement sur ce qui est la bonne quantité d'explication.

On pourrait peut-être sortir un peu de vars à l'auto-documentation du code; comme,

var atLeastOneFilled = module.find(...).length > 0;
if (atLeastOneFilled) {
  var stillMarkedWithErrors = module.find(...).next(...).not(...);
  stillMarkedWithErrors.text("").addClass(...)

(en supposant que j'ai compris le sens de ces morceaux de votre code! :) )

Je ne suis pas exactement sûr de ce "module" signifie, en fait, est-il un nom plus spécifique que vous pourriez donner à cette variable?

Nice code, dans l'ensemble!

2voto

Andrew Roazen Points 361

Parce que la forme, je travaille sur plusieurs régions clonées avec entrées groupées comme celles-ci, j'ai passé un argument supplémentaire à la require_from_group constructeur, l'évolution exactement une ligne de votre addMethod fonction:

var commonParent = $(element).parents(options[2]);

et de cette façon, un sélecteur d'ID ou le nom de l'élément peut être passé qu'une fois:

jQuery.validator.addClassRules("reqgrp", {require_from_group: [1, ".reqgrp", 'fieldset']});

et le validateur va limiter la validation d'éléments avec la classe qu'à l'intérieur de chaque fieldset, plutôt que d'essayer de compter tous les .reqgrp classé les éléments du formulaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X