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});
}
);
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.
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.