最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Jquery filtering with multiple Checkboxes - Stack Overflow

programmeradmin0浏览0评论

For a current project I am creating a simple product catalogue which should be able to be filtered by Jquery with several sets of checkboxes.

In one single set when two or more checkboxes are checked the logic should be OR while when using two or more sets of checkboxes it should be AND.

A good (and working) example I am currently using can be found here:

JSFIDDLE

if (cselector === '' && nselector === '') {
    $('.flowers > div').filter(selector).show();
} else if (cselector === '') {
    $('.flowers > div').filter(selector).filter(nselector).show();
} else if (nselector === '') {
    $('.flowers > div').filter(selector).filter(cselector).show();
} else {
    $('.flowers > div').filter(selector).filter(cselector).filter(nselector).show();
}

My question regards this part of the code where the filters are being used in case they were selected. Now this works pretty good for the 3 filters that are being used in the example. What I am wondering is there some better way to be doing this? In my case I want to add some more filters and then this part of the code will get messy pretty soon when I have to add a lot more if statements.

So basically my question is: Using this setup, how would you add more filters so you have 6 or 7 in the end instead of the current 3?

Thanks a lot, Peter

P.S. I also appreciate tips for completely different approaches but as I already put quite some time into this I would really like to get it work this way.

For a current project I am creating a simple product catalogue which should be able to be filtered by Jquery with several sets of checkboxes.

In one single set when two or more checkboxes are checked the logic should be OR while when using two or more sets of checkboxes it should be AND.

A good (and working) example I am currently using can be found here:

https://stackoverflow.com/a/22941156/5567735

JSFIDDLE

if (cselector === '' && nselector === '') {
    $('.flowers > div').filter(selector).show();
} else if (cselector === '') {
    $('.flowers > div').filter(selector).filter(nselector).show();
} else if (nselector === '') {
    $('.flowers > div').filter(selector).filter(cselector).show();
} else {
    $('.flowers > div').filter(selector).filter(cselector).filter(nselector).show();
}

My question regards this part of the code where the filters are being used in case they were selected. Now this works pretty good for the 3 filters that are being used in the example. What I am wondering is there some better way to be doing this? In my case I want to add some more filters and then this part of the code will get messy pretty soon when I have to add a lot more if statements.

So basically my question is: Using this setup, how would you add more filters so you have 6 or 7 in the end instead of the current 3?

Thanks a lot, Peter

P.S. I also appreciate tips for completely different approaches but as I already put quite some time into this I would really like to get it work this way.

Share Improve this question edited May 23, 2017 at 11:54 CommunityBot 11 silver badge asked Jan 26, 2016 at 9:54 Petey PetePetey Pete 551 gold badge1 silver badge6 bronze badges 4
  • Is it possible you can amend the HTML? This would be much simpler if you had each property to be filtered in its own data attribute. – Rory McCrossan Commented Jan 26, 2016 at 10:08
  • Yes, I can freely change the HTML. Can you explain a bit more detailed how the properties would be filtered in seperated data attributes? Thx! – Petey Pete Commented Jan 26, 2016 at 10:17
  • though it doesn't resemble your current code at all, you could do something like this – billyonecan Commented Jan 26, 2016 at 11:16
  • Thanks @billyonecan that seems to be working just fine and with much less code! I really appreciate it! Is there any way I can mark your comment to be the accepted answer? Cheers – Petey Pete Commented Jan 27, 2016 at 8:16
Add a comment  | 

2 Answers 2

Reset to default 18

Your current approach isn't very dynamic, selectors and arrays are being hardcoded, so each time you add new filter options you'll have to add code to handle it.

Instead, just bind a change handler to all filter checkboxes, you can collect up their values, and group them by their respective names, eg:

var $filterCheckboxes = $( '.filter-checkboxes' );

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

  var selectedFilters = {};

  $filterCheckboxes.filter( ':checked' ).each( function() {

    if ( ! selectedFilters.hasOwnProperty( this.name ) ) {
      selectedFilters[ this.name ] = [];
    }

    selectedFilters[ this.name ].push( this.value );

  } );

} );

This will create an object containing input-name -> value array pairs, eg:

selectedFilters = {
  'fl-colour': [ 'red', 'green' ],
  'fl-size': [ 'tiny' ]
};

You can then loop over each selectedFilters, and filter your .flower elements. If a .flower element matches a value in each named set, we return true so that the element is included in the $filteredResults collection:

// create a collection containing all of the filterable elements
var $filteredResults = $( '.flower' );

// loop over the selected filter name -> (array) values pairs
$.each( selectedFilters, function( name, filterValues ) {

  // filter each .flower element
  $filteredResults = $filteredResults.filter( function() {

    var matched = false,
        currentFilterValues = $( this ).data( 'category' ).split( ' ' );

    // loop over each category value in the current .flower's data-category
    $.each( currentFilterValues, function( _, currentFilterValue ) {

      // if the current category exists in the selected filters array
      // set matched to true, and stop looping. as we're ORing in each
      // set of filters, we only need to match once

      if ( $.inArray( currentFilterValue, filterValues) != -1 ) {
        matched = true;
        return false;
      }

    } );    

    // if matched is true the current .flower element is returned
    return matched;    

  } );

} );

Then simply hide all the .flower elements, and show the $filteredResults, eg:

$( '.flower' ).hide().filter( $filteredResults ).show();

Here's an example fiddle

Here is a fork of the jsfiddle from billyonecan. Differences are...

  • An unchecked box means that property is excluded from results
  • All checkboxes are checked by default (all results shown)
  • At least one checkbox for each filter group must be checked
  • If a filter group does not submit a filter, all results are hidden
  • If a new filter group is added it will be automatically handled

    ( ( a||b||c ) && ( x||y||z ) && ( 1||2||3 )... )

. jsFiddle

var $filterCheckboxes = $('input[type="checkbox"]');

  // Read All Available Filter Groups
  var allFilters = [];
  $filterCheckboxes.each(function() {
  	if ($.inArray(this.name,allFilters) == -1){
    	allFilters.push(this.name);
    }  
  });
//  console.log(allFilters); 






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

  // create a collection containing all of the filterable elements
  var $filteredResults = $('.item');

	var $filterCategoryApplied = 0;
  
  $.each(allFilters, function(arIndex, filterName) {
  // console.log(filterName); 
	var $filterCheckboxCategory = $('input[name='+filterName+']').filter(':checked');
	
  console.log(filterName + ' length = ' + $filterCheckboxCategory.length);
   
   if ( $filterCheckboxCategory.length === 0 ) {
//    alert('none checked for ' + filterName);
    $filteredResults = [];
   }
  });




console.log('start checking');



	// Read Selectetd Filters
  var selectedFilters = {};
  $filterCheckboxes.filter(':checked').each(function() {
    if (!selectedFilters.hasOwnProperty(this.name)) {
      selectedFilters[this.name] = [];
    }
    selectedFilters[this.name].push(this.value);
  });
  
  

  



  // loop over the selected filter name -> (array) values pairs
  $.each(selectedFilters, function(name, filterValues) {

//console.log(selectedFilters['fl-colour'].length); 
//console.log(name); 
//console.log(filterValues); 
//console.log(filterValues.length); 



    // filter each .flower element
    $filteredResults = $filteredResults.filter(function() {

      var matched = false,
        currentFilterValues = $(this).data('category').split(' ');

      // loop over each category value in the current .flower's data-category
      $.each(currentFilterValues, function(_, currentFilterValue) {

        // if the current category exists in the selected filters array
        // set matched to true, and stop looping. as we're ORing in each
        // set of filters, we only need to match once

        if ($.inArray(currentFilterValue, filterValues) != -1) {
          matched = true;
          return false;
        }
      });

      // if matched is true the current .flower element is returned
      return matched;

    });
  });

  $('.item').hide().filter($filteredResults).show();

});
body {
  font-family: 'Arial';
  color: #646464;
}


.items-wrap {
  float: left;
  width: 20%;
  margin: 0 3% 0 0;
  padding: 0;
  position: relative;
}

.items {
  float: left;
  width: 60%;
}

.items div.item {
  float: left;
  width: 45%;
  height: 28px;
  line-height: 38px;
  padding: 0 1%;
  background: #eee;
  margin: 0 0 1px;
  position: relative;
  font-size: 0.7em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<pre id=result> </pre>

<div class="items-wrap">

  <h3 style="font-size:13px; font-weight:normal;">Filter Items</h3>
  <p style="font-size:12px;"><strong>By colour:</strong></p>
  
  <form id='filters'>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-colour" value="red" id="red" checked /> Red</label>
    <br>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-colour" value="yellow" id="yellow" checked /> Yellow</label>
    <br>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-colour" value="green" id="green" checked /> Green</label>

    <p style="font-size:12px;"><strong>By size:</strong></p>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-size" value="small" id="small" checked /> Small</label>
    <br>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-size" value="medium" id="medium" checked /> Medium</label>
    <br>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-size" value="large" id="large" checked /> Large</label>
  
    <p style="font-size:12px;"><strong>By Shape:</strong></p>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-shape" value="square" id="square" checked /> Square</label>
    <br>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-shape" value="circle" id="circle" checked /> Circle</label>
    <br>
    <label style="font-size:12px;">
      <input type="checkbox" name="fl-shape" value="triangle" id="triangle" checked /> Triangle</label>
  </form>

</div>



<div class="items">
  <div class="item" data-id="rss" data-category="red small square">red small square</div>
  <div class="item" data-id="yss" data-category="yellow small square">yellow small square</div>
  <div class="item" data-id="gss" data-category="green small square">green small square</div>
  
  <div class="item" data-id="rms" data-category="red medium square">red medium square</div>
  <div class="item" data-id="yms" data-category="yellow medium square">yellow medium square</div>
  <div class="item" data-id="gms" data-category="green medium square">green medium square</div>
  
  <div class="item" data-id="rls" data-category="red large square">red large square</div>
  <div class="item" data-id="yls" data-category="yellow large square">yellow large square</div>
  <div class="item" data-id="gls" data-category="green large square">green large square</div>







  <div class="item" data-id="rsc" data-category="red small circle">red small circle</div>
  <div class="item" data-id="ysc" data-category="yellow small circle">yellow small circle</div>
  <div class="item" data-id="gsc" data-category="green small circle">green small circle</div>
  
  <div class="item" data-id="rmc" data-category="red medium circle">red medium circle</div>
  <div class="item" data-id="ymc" data-category="yellow medium circle">yellow medium circle</div>
  <div class="item" data-id="gmc" data-category="green medium circle">green medium circle</div>
  
  <div class="item" data-id="rlc" data-category="red large circle">red large circle</div>
  <div class="item" data-id="ylc" data-category="yellow large circle">yellow large circle</div>
  <div class="item" data-id="glc" data-category="green large circle">green large circle</div>
  
  
  
  
  
  <div class="item" data-id="rst" data-category="red small triangle">red small triangle</div>
  <div class="item" data-id="yst" data-category="yellow small triangle">yellow small triangle</div>
  <div class="item" data-id="gst" data-category="green small triangle">green small triangle</div>
  
  <div class="item" data-id="rmt" data-category="red medium triangle">red medium triangle</div>
  <div class="item" data-id="ymt" data-category="yellow medium triangle">yellow medium triangle</div>
  <div class="item" data-id="gmt" data-category="green medium triangle">green medium triangle</div>
  
  <div class="item" data-id="rlt" data-category="red large triangle">red large triangle</div>
  <div class="item" data-id="ylt" data-category="yellow large triangle">yellow large triangle</div>
  <div class="item" data-id="glt" data-category="green large triangle">green large triangle</div>  
  



</div>

发布评论

评论列表(0)

  1. 暂无评论