Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
565 views
in Technique[技术] by (71.8m points)

jquery - Combining elements for filtering with Isotope

I'm currently using Isotope to filter a list of publications, but would like to be able to combine the standard, documented link-filter method with a select element, as my second list of filters is quite long.

The bit I'm struggling with is dealing with two distinct types of element and combining selected values into one option array. I can make the filters work independently of each other (code below) but they need to work together. How can I combine the two different actions (click or change) and two attributes (class= or value=) into one options array to pass to the isotop filter?

    var $container = $('#library');
// select ccskills publications by default
$container.isotope({ filter: '.ccskills' });

var $optionSets = $('#library-options .option-set'),
$optionLinks = $optionSets.find('a');

$optionLinks.click(function(){
    var $this = $(this);
    // don't proceed if already selected
    if ( $this.hasClass('selected') ) {
    return false;
    }
    var $optionSet = $this.parents('.option-set');
    $optionSet.find('.selected').removeClass('selected');
    $this.addClass('selected');

    // make option object dynamically, i.e. { filter: '.my-filter-class' }
    var options = {},
    key = $optionSet.attr('data-option-key'),
    value = $this.attr('data-option-value');

    // parse 'false' as false boolean
    value = value === 'false' ? false : value;
    options[ key ] = value;
    $container.isotope( options );
    return false;
});

    // using the 'chozen' plugin to style my select element
$(".chzn-select").chosen().change(
    function() {
        var industry = $("option:selected", this).val();
        $container.isotope({filter: industry});
    }
);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need a multi-dimensional array, with an array dimension for each filter type you have. I've done that before and there's a live demo example here!

See here! for the js.

EDIT (Feb, 2020): Links to demo and JavaScript have been updated for 2020 with wayback machine urls

In my js file you'll be interested in the end function called getComboFilters( filters )

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++;
    }
    comboFilters.sort();
    var comboFilter = comboFilters.join(', ');
    return comboFilter;
}

This function handles all of the pushing, splicing and sorting of the various sets of filter arrays but to use it you need to add it to your filter routine... well I say routine but it routines really because you seem to call the filter method 2 separate times:

$container.isotope({ filter: '.ccskills' });

and later:

 $container.isotope({filter: .industry});

If your going to filter types together all of your filter types are going to have to know about each other, meaning they're going to have to be inside the same javascript enclosure and the filter method needs to be called only once at which time it gets tested against all your filter type conditions.

using the getComboFilter( filters ) function you call the combination filter method like this:

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

Finally, the full integration into your file would be somethign like this:

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

// This next part targets all the possible filter items
// i.e. '.option-set a' just like your example

$('.option-set a').click(function(){
        // exit directly if filter already disabled
        if ($(this).hasClass('disabled') ){
            return false;
        }
        var $this = $(this);
        var $optionSet = $(this).parents('.option-set');
        var group = $optionSet.attr('data-filter-group');
        // store filter value in object
        var filterGroup = filters[ group ];
        if ( !filterGroup ) {
            filterGroup = filters[ group ] = [];
        }
        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++;
    }
    comboFilters.sort();
    var comboFilter = comboFilters.join(', ');
    return comboFilter;
}

Hope this helps somebody! The demo is pretty slick.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...