kittonian
kittonian

Reputation: 1421

Parsley JS - Custom Validator for Minimum Number of Select Set to Value

I have a form where I need to validate that there are at least 5 select boxes set to Yes (or . If there are more that's fine, but if there are less I need it to not submit the form and show an error. Thus, I need a custom validator.

I've created a jsfiddle to show a full example https://jsfiddle.net/kittonian/v9w8rgeb/


Additionally, here is the sample code:

<html>
<head></head>
<body>

<form name="select_test" id="postfeatured" method="post" action="#">

<div class="choice">

<div>
<select name="post_featured1" id="post_featured1" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="1">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured2" id="post_featured2" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="2">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured3" id="post_featured3" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="3">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured4" id="post_featured4" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="4">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured5" id="post_featured5" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="5">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured6" id="post_featured6" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="6">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>
</div>

<div class="submit">
<input type="submit" value="SUBMIT" class="submitbutton">
</div>

</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/parsley.js/2.9.2/parsley.min.js" integrity="sha512-eyHL1atYNycXNXZMDndxrDhNAegH2BDWt1TmkXJPoGf1WLlNYt08CSjkqF5lnCRmdm3IrkHid8s2jOUY4NIZVQ==" crossorigin="anonymous"></script>

</body>
</html>

And here is the current JS invoking Parsley. It is only validating the duplicates and not checking if 5 select boxes are set to Yes. I also need the error message to only show up on the select boxes set to No.

var validating;

$("#postfeatured").parsley();

$('select.enabled').change(()=>{
 if(!validating) return; $("#postfeatured").parsley().validate({group:'minselect'});
});

window.Parsley.addValidator("enabled", {
      validateMultiple: function(values) {
        return values.length > 0;
      },
    requirementType: "string",
    validateString: function(value, current) {
      validating=true;
     var els=$('select[id^="post_featured"]');
     ar=[];
     for(let i=0;i<els.length;i++) ar.push(jQuery(els[i]).val());
      // first simply find if there are any dupes
      // https://stackoverflow.com/a/7376645
      // https://www.geeksforgeeks.org/how-to-convert-set-to-array-in-javascript/
     var sar=Array.from(new Set(ar));
     if(sar.length !== ar.length){
      // there are dupes
       // returning false here makes ALL fields show an error, so we have to find out which ones are dupes and check if current is one of them
       // for each filtered (Set array) value, check if more than one and if so return false if equal to current field value
       for(let i=0;i<sar.length;i++){
         var cnt=0;
         for(let j=0;j<ar.length;j++){
           if(ar[j]===sar[i]) cnt++;
         }
         if(cnt>1 && $('#post_featured'+current).val()==sar[i]) return false;
       }
     }
     return true;
   },
   priority: 33,
   messages: {en: 'You must have at least 5 featured posts'}
});

Upvotes: 0

Views: 1316

Answers (2)

kittonian
kittonian

Reputation: 1421

Got it working. Here's how to do it.

HTML:

<html>
<head></head>
<body>

<form name="select_test" id="postfeatured" method="post" action="#">

<div class="choice">

<div>
<select name="post_featured1" id="post_featured1" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="1">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured2" id="post_featured2" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="2">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured3" id="post_featured3" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="3">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured4" id="post_featured4" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="4">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured5" id="post_featured5" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="5">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>

<div>
<select name="post_featured6" id="post_featured6" class="select enabled" data-parsley-group="minselect" data-parsley-enabled="6">
<option value="t">Y</option>
<option value="f">N</option>
</select>
</div>
</div>

<div class="submit">
<input type="submit" value="SUBMIT" class="submitbutton">
</div>

</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/parsley.js/2.9.2/parsley.min.js" integrity="sha512-eyHL1atYNycXNXZMDndxrDhNAegH2BDWt1TmkXJPoGf1WLlNYt08CSjkqF5lnCRmdm3IrkHid8s2jOUY4NIZVQ==" crossorigin="anonymous"></script>

</body>
</html>

JS:

var validating;

$("#post_featured").parsley();

$('select.enabled').change(() => {
  if (!validating) return;
  $("#post_featured").parsley().validate({
    group: 'minselect'
  });
});

window.Parsley.addValidator("enabled", {
  validateMultiple: function(values) {
    return values.length > 0;
  },
  requirementType: "string",
  validateString: function(value, current) {
    validating = true;
    var currentYesCount = $('#post_featured select').filter(function() {
      return $(this).val() === 't';
    }).length;
   if (value === 't') {
     return true;
    } else {
      if (currentYesCount > 4) {
        return true;
      } else {
        return false;
      }}
  },
  priority: 33,
  messages: {
    en: 'You must have at least 5 posts set to Yes'
  }
});

Upvotes: 0

Marc-Andr&#233; Lafortune
Marc-Andr&#233; Lafortune

Reputation: 79552

Validation depending on multiple inputs is not easy.

There is no builtin way to do this.

You can write your own custom validator. You may want to inspire yourself from this example

Upvotes: 0

Related Questions