Isotope: combination filtering + multiple selection

自闭症网瘾萝莉.ら 提交于 2019-12-05 07:08:48

问题


To all jQuery heros out there, I need help! (again)

I found similar questions to mine on the internet but there were no answers so far :-/

I want to filter a bunch of items with jquery isotope. I adapted the combination filter example from the plugin homepage, which works fine and looks like so:

$(function () {
var $container = $('#container'),
    filters = {};
$container.isotope({
    itemSelector: '.item',
    filter: '',
});

// filter links
$('.filter a').click(function () {
    var $this = $(this);
    // don't proceed if already selected
    if ($this.hasClass('selected')) {
        return;
    }

    var $optionSet = $this.parents('.option-set');
    // change selected class
    $optionSet.find('.selected').removeClass('selected');
    $this.addClass('selected');

    // store filter value in object
    // i.e. filters.color = 'red'
    var group = $optionSet.attr('data-filter-group');
    filters[group] = $this.attr('data-filter-value');

    // convert object into array
    var isoFilters = [];
    for (var prop in filters) {
        isoFilters.push(filters[prop])
    }
    var selector = isoFilters.join('');
    $container.isotope({
        filter: selector
    });
    return false;
}); });

and some html of the filter menu:

<div id="nav">
    <ul class="filter option-set" data-filter-group="who">
        <li><a href="#filter-who-any" data-filter-value="" class="selected">Any</a></li>
        <li><a href="#filter-who-boys" data-filter-value=".boys">Boys</a></li>
        <li><a href="#filter-who-girls" data-filter-value=".girls">Girls</a></li>
    </ul>

</div>

I set up a fiddle demo with 3 filter categories which can be combined: jsFiddle

Now I'd like to make it possible to select multiple tags from each category:

Category 1: a OR b OR c

AND

Categoy 2: a OR b OR c

AND

Categoy 3: a OR b OR c

There's a check-box-example by desandro, but this is not quite the thing I'm searching for, because I want to keep the AND condition between the categories. Basically I want 3 filter categories with some check-boxes for each of them (or links but I guess check-boxes are more functional). I think the methods used in both examples are completely different and I don't know how to combine their functionality.

I hope you get my point and that anyone could help me find a solution.

Thanks in advance!


回答1:


Using multiple filter types with metafizzy isotope filtering requires a multi-dimensional array to hold an array of each filter type.

I have a live example here

And js for the example is here

For a full code explanation see my answer to this question




回答2:


have a look here

http://codepen.io/desandro/pen/btFfG

it's the same answer by DrewT but from the Isotope team.

all you have to do in order to filter is put every group under same object

        var filters = {};//sould be outside the scope of the filtering function


  $a.click(function(){//filtering function
                var group = $optionSet.attr('data-filter-group');
             var filterGroup = filters[group];
                              if (!filterGroup) {
                                  filterGroup = filters[group] = [];
                              }
         filters[ group ].push($this.attr('data-filter-value'));
  })

now all you have to do is call getComboFilter function(you don't have to understand the code inside getComboFilter, think of it as a part of isotope)

     var comboFilter = getComboFilter( filters );
 $container.isotope({ filter: comboFilter});

function getComboFilter( filters ) {
  var i = 0;
  var comboFilters = [];
  var message = [];

  for ( var prop in filters ) {
    message.push( filters[ prop ].join(' ') );
    var filterGroup = filters[ prop ];
    // skip to next filter group if it doesn't have any values
    if ( !filterGroup.length ) {
      continue;
    }
    if ( i === 0 ) {
      // copy to new array
      comboFilters = filterGroup.slice(0);
    } else {
      var filterSelectors = [];
      // copy to fresh array
      var groupCombo = comboFilters.slice(0); // [ A, B ]
      // merge filter Groups
      for (var k=0, len3 = filterGroup.length; k < len3; k++) {
        for (var j=0, len2 = groupCombo.length; j < len2; j++) {
          filterSelectors.push( groupCombo[j] + filterGroup[k] ); // [ 1, 2 ]
        }

      }
      // apply filter selectors to combo filters for next group
      comboFilters = filterSelectors;
    }
    i++;
  }

  var comboFilter = comboFilters.join(', ');
  return comboFilter;
}



回答3:


Here is the JS Fiddle code you can follow for Isotope Combination Filter with multiple select dropdown

$(document).ready(function(){
  // init Isotope
  var $grid = $('.grid').isotope({
    itemSelector: '.item'
  });

  // store filter for each group
  var filters = {};

  $('.filters').on('change', '.filters-select', function(){
    var $this = $(this);
    var filterGroup = $this.attr('data-filter-group');
    filters[ filterGroup ] = $this.val();
    var filterValue = concatValues( filters );
    $grid.isotope({ filter: filterValue });
  });

  // flatten object by concatting values
  function concatValues( obj ) {
    var value = '';
    for ( var prop in obj ) {
      value += obj[ prop ];
    }
    return value;
  }
});

https://jsfiddle.net/srikanthLavudia/vhrbqn6p/




回答4:


I could make it work but it was not as straightforward as I thought in a firts instance. I think you need to bear on mind a couple of things:

  1. If you want to use a restrictive AND condition, then I suggest don´t use the "data-filter-value" option. Instead, put your filter variables as classes. Then, you will need to fire the isotope function by yourself in the onclick event. This is because otherwise you will fire the "default" isotope function when the user clicks the button and you won´t be able to achieve the restrictive AND mentioned.

  2. In the same direction, you will need to use new variable names (so new classes) for each combination of nested filter options you are going to work with. Otherwise, I don´t see other way (at the moment) to get a restrictive AND condition.

This concept about restrictive and nonrestrictive AND clauses is like the difference between an outer and an inner join. It's the concept you should use if you want to handle two filters, one subfilter of the other one.
One example would be something like a list of ebooks which could be filtered by brand, an other subfilter based on the different range prices they belong to.

I show you below a code example where I implement this idea, it can give you a hint of what i mean:

HTML:

<!--Filters section -->
<div id="filters">
    <ul id="optionSet1" class="option-set" data-option-key="filter">
           <li><a id="filter10" href="#filter" class="selected">Everything</a></li>
        <c:forEach var="brand" items="${brands}" varStatus="status" >
             <li><a id="filter1${status.count}" href="#filter" class='${brand}'>${brand}</a></li>
        </c:forEach>
    </ul>
    <ul id="optionSet2" class="option-set" data-option-key="filter">
        <li><a id="filter20" href="#filter" class="selected">Any Price</a>  </li>
    <c:forEach var="brandPrice" items="${brandPrices}" varStatus="status" >
        <li><a id="filter2${status.count}" href="#filter" class='${brandPrice}'>${brandPrice}</a></li>
    </c:forEach>
    </ul>
</div>  


<!--Elements to filter -->
<div id="portfolio-wrapper" class="row">
    <c:forEach var="publication" items="${publications}" varStatus="status" >               
        <div class='span4 portfolio-item ${publication.filterOption1} ${publication.filterOption2} ${publication.filterOption3}...'>
<!-- filterOption3 would be the combination of filterOption1 and filterOption2, you can make this building a string as the addition of filterOption1 and filterOption2 strings-->
            <!--Content to display-->           
    </c:forEach>
</div>

javascript:

$(function(){

        $("a[id^='filter1']").on('click', function() {
//          alert($(this).attr('class'));
//          alert($('#optionSet2 .selected').attr('class'));
            var myclass = $('#optionSet2 .selected').attr('class');
            myclass = myclass.replace(' selected','');
            myclass = myclass.replace('selected','');
            var myclass2 = $(this).attr('class');
            myclass2 = myclass2.replace(' selected','');
            myclass2 = myclass2.replace('selected','');
            if($(myclass=='' && myclass2==''){
                $('#portfolio-wrapper').isotope({ filter: '*'});
            }else if(myclass==''){
                $('#portfolio-wrapper').isotope({ filter: '.'+ myclass2+'' });
            }else if(myclass2==''){
                $('#portfolio-wrapper').isotope({ filter: '.'+myclass+'' });
            }else{

                $('#portfolio-wrapper').isotope({ filter: '.'+myclass2+myclass+''});
            }   
        });

        $("a[id^='filter2']").on('click', function() {
//          alert($(this).attr('class'));
//          alert($('#optionSet1 .selected').attr('class'));
            var myclass = $('#optionSet1 .selected').attr('class');
            myclass = myclass.replace(' selected','');
            myclass = myclass.replace('selected','');
            var myclass2 = $(this).attr('class');
            myclass2 = myclass2.replace(' selected','');
            myclass2 = myclass2.replace('selected','');
            if(myclass=='' && myclass2==''){
                $('#portfolio-wrapper').isotope({ filter: '*'});
            }else if(myclass==''){
                $('#portfolio-wrapper').isotope({ filter: '.'+ myclass2+'' });
            }else if(myclass2==''){
                $('#portfolio-wrapper').isotope({ filter: '.'+myclass+'' });
            }else{

                $('#portfolio-wrapper').isotope({ filter: '.'+myclass+myclass2+''});
            }
        });

});



回答5:


Sorry to dredge this question up, but I recently ran into the same problem and (imho) wasted a lot of time solving this with combined selectors. (Combine every class from array A with every class from array B, etc.)

Use a filtering function. It allows arbitrary complexity and is probably the right choice for all non-trivial cases.

Most importantly, there is no performance benefit to using selectors (which you might expect if the selector were fed directly into a querySelector or jQuery call). Isotope iterates through each item and applies the selector as a function regardless:

return function( item ) {
  return matchesSelector( item.element, filter );
};

Therefore, you might as well just put your filtering logic into a function instead of trying to generate a selector string.



来源:https://stackoverflow.com/questions/17553076/isotope-combination-filtering-multiple-selection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!