tadasajon
tadasajon

Reputation: 14856

JavaScript Isotope - How can I intelligently create multiple groups of filters to work together on one container?

Lets say I want to filter on both color (red, yellow, or blue) and on size (small, medium, or large) and on material (wool, cotton, silk). I will have three sets of checkboxes. If a user checks the "red" checkbox and the "medium" checkbox, I want Isotope to display items that are both red and medium. So far, no problem. But what if the user checks both the red and yellow checkboxes as well as both the medium and large checkboxs and both the wool and silk checkboxes? Now I want Isotope to display items that are ((medium OR large) AND (red OR yellow) AND (wool OR silk)).

Building a jQuery selector string to fit this scenario seems complicated to me, especially if there are dozens of groups, each containing dozens of options.

With jQuery alone I could do the following:

$('.medium, .large').filter('.red, .yellow').filter('.wool, .silk');

But if I have to build the whole selector only one time in order to pass it fully-formed to Isotope, I would have to do:

`.medium.red.wool, .medium.red.silk, .medium.yellow.wool, .medium.yellow.silk, .large.red.wool, .large.red.silk, .large.yellow.wool, .large.yellow.silk`

As you can see, with two items selected from three groups I have 2^3 comma-separated strings in my selector. Now imagine I have six filtering groups:

Color (red, blue, yellow, green, purple, black)
Size (tiny, small, medium, biggish, large, extra-large)
Price (very-cheap, cheap, medium, expensive, very-expensive, extraordinarily-expensive)
Material (cotton, wool, satin, linen, felt, wood, iron)
Type (archer, hunter, wizard, mage, spy, druid)
Popularity (not-popular, mildly-popular, somewhat-popular, medium-popular, quite-popular, very-popular)

And let's say the user checks the first five options in each group. My selector string would have to contain 5^6 comma-separated strings, each one containing six terms. If each term averaged 5 characters, with five .s separating them, then I would have 5^6 strings, each 35 characters long, for a total length of my selector around 546,875 characters.

Does Isotope provide a better way for me to solve this problem?

Upvotes: 3

Views: 851

Answers (1)

Esailija
Esailija

Reputation: 140230

the jQuery .filter accepts a function as well, not just a selector string, so you could make a function.

$elem.isotope({
    filter: function() {
        var $this = $(this);
        return $this.is('.medium, .large') && $this.is('.red, .yellow') && $this.is('.wool, .silk');
    }
});

Looking at isotope source code, it seems like it should work since they pass the filter parameter to jQuery filter method.

You can make a function like that on the fly by passing a selectors array:

function makeFilterFunction( selectorsArray ) {
    var length = selectorsArray.length;
    return function() {
        var $this = $(this);

        for( var i = 0; i < length; ++i ) {
            if( !$this.is( selectorsArray[i] ) ) {
                return false;
            }
        }

        return true;
    };
}

Then:

$elem.isotope({
    filter: makeFilterFunction(['.medium, .large', '.red, .yellow', '.wool, .silk'])
});

Is the dynamic equivalent of the static code at the start of my answer.

Upvotes: 6

Related Questions