0

I have checkboxes to filter what DIVs appear on the page. I have the code in this fiddle and also below.

This code works, but the issue is with the "Country" checkboxes. If you uncheck "Argentina," the blue div goes away. But it should stay because it also has "Brazil" and "Mexico" in its data-country field.

In other words, the blue div should only disappear if ALL three checkboxes under "Country" are unchecked.

I believe this is happening because my code loops through the CHECKED checkboxes first and shows them, and THEN loops through the UNCHECKED checkboxes and hides them. So it's seeing Brazil and Mexico are checked and shows technically shows them for a split second, but then immediately sees Argentina is unchecked, so it ultimately hides it.

My thought was to reverse the order in how I'm looping through, i.e. loop through UNCHECKED first and then CHECKED. So I switched that in the Jquery but it stopped working at all. No idea why that would break it.

If anyone has any ideas on how to do this properly and/or how to make it work if I reverse the order of how I'm looping, please let me know.

HTML:

<div class="Row sel" style="background: #eeeeee;" data-region="Americas" data-country="Brazil" data-tier="Elite Reseller">
<div class="Heading">Allegiant Technology</div>
<div class="Copy">Brazil</div>
<div class="Copy">Elite Reseller</div>
</div>

<div class="Row sel" style="background: red;" data-region="APAC" data-country="Mexico" data-tier="Preferred Reseller">
<div class="Heading">Folco Communications</div>
<div class="Copy">Mexico</div>
<div class="Copy">Preferred Reseller</div>
</div>
<div class="Row sel" style="background: blue;" data-region="EMEA" data-country="Argentina, Mexico, Brazil" data-tier="Authorized Reseller">
<div class="Heading">Latin Telecom</div>
<div class="Copy">Argentina; Mexico; Brazil</div>
<div class="Copy">Authorized Reseller</div>
</div>


<div style="text-align:left; max-width: 1000px;  margin-left: auto;  margin-right: auto;  padding-left: 50px;">
<span class="title">Region:</span><br>
<input class="css-checkbox" type="checkbox" id="APAC" data-type="region" data-value="APAC" checked > 
<label for="APAC" class="css-label">APAC</label>
<input class="css-checkbox" type="checkbox" id="EMEA" data-type="region" data-value="EMEA" checked>
<label for="EMEA" class="css-label">EMEA</label>
<input class="css-checkbox" type="checkbox" id="Americas" data-type="region" data-value="Americas" checked>
<label for="Americas" class="css-label">Americas</label>
<br>
<br>
<span class="title">Partner Type:</span><br>
<input class="css-checkbox" type="checkbox" id="Preferred" data-type='tier'  data-value='Preferred Reseller' checked>
<label for="Preferred" class="css-label">Preferred</label>
<input class="css-checkbox" type="checkbox" id="Elite" data-type='tier'  data-value='Elite Reseller' checked>
<label for="Elite" class="css-label">Elite</label>
<input class="css-checkbox" type="checkbox" id="Authorized" data-type='tier'  data-value='Authorized Reseller' checked>
<label for="Authorized" class="css-label">Authorized</label>
<br>
<br>
<span class="title">Country:</span><br>
<input class="css-checkbox" type="checkbox" id="Argentina" data-type='country'  data-value='Argentina' checked>
<label for="Argentina" class="css-label">Argentina</label>
<input class="css-checkbox" type="checkbox" id="Brazil" data-type='country'  data-value='Brazil' checked>
<label for="Brazil" class="css-label">Brazil</label>
<input class="css-checkbox" type="checkbox" id="Mexico" data-type='country'  data-value='Mexico' checked>
<label for="Mexico" class="css-label">Mexico</label>
</div>

JS:

$('[type="checkbox"]').on('change', function () {
  $('[type="checkbox"]:checked').each( function (ind, inp) { //loop over checked checkboxes
    var type = inp.dataset.type, value = inp.dataset.value; 
    $('div[data-' + type +'*="' + value +'"]').show();  
  })
  $('[type="checkbox"]:not(:checked)').each( function (ind, inp) { //loop over unchecked checkboxes
    var type = inp.dataset.type, value = inp.dataset.value; 
    $('div[data-' + type +'*="' + value +'"]').hide();  
  })    

});
user3304303
  • 1,027
  • 12
  • 31
  • You are not only looping through country checkboxes but also tier and region. – Ibrahim Khan Oct 19 '18 at 18:43
  • Aren't I able to loop through all of them each time something is checked or unchecked? Or should I only be looping through the specific data-type on the input that was manipulated? – user3304303 Oct 19 '18 at 18:53
  • I mean, you uncheck all countries but `EMEA` or `Authorized` are still checked. That's why blue div is still showing. – Ibrahim Khan Oct 19 '18 at 19:10
  • Do you want the content areas to show that match *any* of the checked boxes? – showdev Oct 19 '18 at 19:17
  • No, which I guess is the problem here. If a company in APAC is an Elite Reseller, if Elite Reseller is checked, but APAC is NOT Checked, then they shouldn't show. – user3304303 Oct 19 '18 at 19:34
  • It seems like checking for unchecked last is the right way to do it,but then because the Countries work differently (i.e. they can have more than one country they are associated with) it gets screwed up. This seemed so simple at first but is getting more complicated :) – user3304303 Oct 19 '18 at 19:36
  • So, for each reseller, *all* of its attributes must be checked for it to show? Or are some attributes required and others aren't? Sorry if I'm asking you to repeat yourself; I'm just not clear on the desired logic. – showdev Oct 19 '18 at 19:46
  • 1
    Don't be sorry, this is my fault as I'm clearly not explaining it properly. But yes, what you said is correct. For a reseller's div to appear, it's Region must be checked AND it's Partner Type must be checked AND at least one of it's Countries must be checked. Obviously that last little caveat of "at least one of" is causing me issues because I'm currently checking for UNCHECKED boxes last and if it finds one, it hides the div. So even if Brazil and Argentina are checked, if it sees Mexico is unchecked, it's hiding that blue div (when it shouldn't). Does that clear it up? – user3304303 Oct 19 '18 at 20:00

1 Answers1

1

Here is one possible solution:

The crux of this method is comparing two arrays.
I'm using some prototype functions found in this answer by user It's me ... Alex.

The idea is to compare each resellers attributes with the checked values.
Resellers are only shown if at least one attribute of each type is checked.

I build an array of checked values, organized by type in a multidimensional array.
Then I compare each resellers attributes to those values.
If at least one value of each type is checked, that reseller is shown.

Array.prototype.indexOfAny = function(array) {
  return this.findIndex(function(v) {
    return array.indexOf(v) != -1;
  });
}

Array.prototype.containsAny = function(array) {
  return this.indexOfAny(array) != -1;
}



function getAllChecked() {

  // build a multidimensional array of checked values, organized by type

  var values = [];
  var $checked = $checkboxes.filter(':checked');

  $checked.each(function() {

    var $check = $(this);
    var type = $check.data('type');
    var value = $check.data('value');

    if (typeof values[type] !== "object") {
      values[type] = [];
    }

    values[type].push(value);

  });

  return values;

}

function evaluateReseller($reseller, checkedValues) {

  // Evaluate a selected reseller against checked values.
  // Determine whether at least one of the reseller's attributes for
  // each type is found in the checked values.

  var data = $reseller.data();
  var found = false;

  $.each(data, function(prop, values) {

    values = values.split(',').map(function(value) {
      return value.trim();
    });

    found = prop in checkedValues && values.containsAny(checkedValues[prop]);

    if (!found) {
      return false;
    }

  });

  return found;

}


var $checkboxes = $('[type="checkbox"]');
var $resellers = $('.Row.sel');

$checkboxes.on('change', function() {

  // get all checked values.
  var checkedValues = getAllChecked();

  // compare each resellers attributes to the checked values.
  $resellers.each(function(k, reseller) {

    var $reseller = $(reseller);
    var found = evaluateReseller($reseller, checkedValues);

    // if at least one value of each type is checked, show this reseller.
    // otherwise, hide it.

    if (found) {
      $reseller.show();
    } else {
      $reseller.hide();
    }

  });

});
#reseller_allegiant {
  background: lightgreen;
}

#reseller_folco {
  background: pink;
}

#reseller_latin_telecom {
  background: lightblue;
}

#controls {
  text-align: left;
  max-width: 1000px;
  margin: 2em auto 0;
  padding-left: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="Row sel" id="reseller_allegiant" data-region="Americas" data-country="Brazil" data-tier="Elite Reseller">
  <div class="Heading">Allegiant Technology</div>
  <div class="Copy">Brazil</div>
  <div class="Copy">Elite Reseller</div>
</div>

<div class="Row sel" id="reseller_folco" data-region="APAC" data-country="Mexico" data-tier="Preferred Reseller">
  <div class="Heading">Folco Communications</div>
  <div class="Copy">Mexico</div>
  <div class="Copy">Preferred Reseller</div>
</div>

<div class="Row sel" id="reseller_latin_telecom" data-region="EMEA" data-country="Argentina, Mexico, Brazil" data-tier="Authorized Reseller">
  <div class="Heading">Latin Telecom</div>
  <div class="Copy">Argentina; Mexico; Brazil</div>
  <div class="Copy">Authorized Reseller</div>
</div>

<div id="controls">
  <span class="title">Region:</span><br>
  <input class="css-checkbox" type="checkbox" id="APAC" data-type="region" data-value="APAC" checked>
  <label for="APAC" class="css-label">APAC</label>
  <input class="css-checkbox" type="checkbox" id="EMEA" data-type="region" data-value="EMEA" checked>
  <label for="EMEA" class="css-label">EMEA</label>
  <input class="css-checkbox" type="checkbox" id="Americas" data-type="region" data-value="Americas" checked>
  <label for="Americas" class="css-label">Americas</label>
  <br>
  <br>
  <span class="title">Partner Type:</span><br>
  <input class="css-checkbox" type="checkbox" id="Preferred" data-type='tier' data-value='Preferred Reseller' checked>
  <label for="Preferred" class="css-label">Preferred</label>
  <input class="css-checkbox" type="checkbox" id="Elite" data-type='tier' data-value='Elite Reseller' checked>
  <label for="Elite" class="css-label">Elite</label>
  <input class="css-checkbox" type="checkbox" id="Authorized" data-type='tier' data-value='Authorized Reseller' checked>
  <label for="Authorized" class="css-label">Authorized</label>
  <br>
  <br>
  <span class="title">Country:</span><br>
  <input class="css-checkbox" type="checkbox" id="Argentina" data-type='country' data-value='Argentina' checked>
  <label for="Argentina" class="css-label">Argentina</label>
  <input class="css-checkbox" type="checkbox" id="Brazil" data-type='country' data-value='Brazil' checked>
  <label for="Brazil" class="css-label">Brazil</label>
  <input class="css-checkbox" type="checkbox" id="Mexico" data-type='country' data-value='Mexico' checked>
  <label for="Mexico" class="css-label">Mexico</label>
</div>
showdev
  • 28,454
  • 37
  • 55
  • 73
  • This appears to work exactly as I would like, so thank you so much. On first glance, the code confuses me a bit, but that's all on me and my inexperience. Your comments help significantly and I will dive into it later until it makes perfect sense :) Thanks again for your help! – user3304303 Oct 21 '18 at 15:02