Content Filter + Refine with Multi-Category Select (show selected or hide selected)
by
, 04-20-2016 at 07:02 AM (12846 Views)
Back in September last year, I wrote about making a content filter where items are filtered by class. A big limitation to this script is that it uses radio buttons to make selections, and as we all know, only one radio button can be selected at any time.
I decided to revisit the content filter, adding 'refine' functionality, so that multi-category selections can be made. A welcome refinement, and much more usable in the real world for sure.
First I should draw your attention to the first comment on my earlier blog, which pointed to my revised single-category filter script. I didn't elaborate on the changes to the JavaScript before, but I'll briefly cover them here because a similar logic will be used on the latest script version. In fact, it is this progression of logic that lead me to develop the new multi-category selections filter.
After the inital setup of a few helper functions to add and delete classes, the part of the script that performs the filter function looks like this;The line in red identifies the id of the selected filter-category radio, while the line in green takes this id and assembles a CSS selectorCode:document.getElementById('filter-categories').onclick = function(evt) { evt = evt || window.event; var elem = evt.target || evt.srcElement; var filter = (elem.id == 'filter-all') ? '' : '.'+elem.id; var mask = document.querySelectorAll('#filter-mask'); addClassAll(mask, 'filter-mask'); setTimeout(function() { delClassAll(document.querySelectorAll('.filter-item'), 'selected'); addClassAll(document.querySelectorAll('.filter-wrap'), 'filtered'); addClassAll(document.querySelectorAll('.filter-item'+filter), 'selected'); }, 500); setTimeout(function() { delClassAll(mask, 'filter-mask'); }, 1000); }.filter-item.blue
, in order to apply the ".selected" class to those filter-items. Once the class is applied via JS, the CSS kicks in to reveal the selected items;It is this CSS selector that started my brain cogs a-turning - if I could select multiple categories (using checkboxes instead of radios), and chain their selectors thuslyCode:.filtered .filter-item { display:none } .filtered .filter-item.selected { display:block } /* selected class applied via js */.filter-item.blue.red.green
, I could target them with CSS in the same way. So from that spawned...
DEMO - JavaScript & CSS3 Content Filter + Refine with Multi-Category Select: http://fofwebdesign.co.uk/template/_...r-multi-js.htm
Now, this new demo has an inclusive and exclusive filtering option;
- The inclusive filter shows items that have *all* of the selected category classes (works in all browsers but no fade effect in IE8/9).
- The exclusive filter shows items that have *none* of the selected category classes (works in all modern browsers (IE9+) owing to the use of the :not() CSS selector, but has no fade effect in IE9).
It is the inclusive part of the filter JS that uses the chained selector logic mentioned earlier. The idea here is that I can add the selected checkbox filter ids to an array;And then use this array, along with the join() method, to build a CSS selector;Code:for (var i = 1; i < inputs.length; ++i) { // loop through inputs but ignore [0] - #filter-all if (inputs[i].checked) { filters.push(inputs[i].id); } // add checked inputs to filters array }Here's the resulting CSS selectorCode:addClassAll(document.querySelectorAll(id+' .filter-item.'+filters.join('.')), 'selected');} // build css selector from filters array#demo .filter-item.mild.veg
- it is targetting all the filter-items that have both a ".mild" and ".veg" class, and the addClassAll() function is then giving them a ".selected" class. The CSS takes over at this point, in much the same way as the earlier incarnation of the script, to reveal those selected item;The exclusive filter works slightly differently. It loops through the selected checkbox filter id array, and applies the ".selected" class to all the items individually, resulting in a single filter-category selector for each selected filter-itemCode:.filtered-inclusive .filter-item, .filtered-exclusive .filter-item { display:none } /* filtered-inclusive/filtered-exclusive class applied via js */ .filtered-inclusive .filter-item.selected, .filtered-exclusive .filter-item:not(.selected) { display:block } /* selected class applied via js */#demo .filter-item.veg
;The CSS for the exclusive filter is also different - it uses the :not() selector to reveal filter-items that *do not* have the ".selected" class applied;Code:for (var i = 0; i < filters.length; ++i) { addClassAll(document.querySelectorAll(id+' .filter-item.'+filters[i]), 'selected'); }The CSS :not() selector is unsupported in IE8, so please bear in mind that the exclusive filter option will not work in that browser. The inclusive filter uses fully supported selectors though, so will work fine in IE8.Code:.filtered-inclusive .filter-item, .filtered-exclusive .filter-item { display:none } /* filtered-inclusive/filtered-exclusive class applied via js */ .filtered-inclusive .filter-item.selected, .filtered-exclusive .filter-item:not(.selected) { display:block } /* selected class applied via js */
Last thing - the new content filter script been written as a function so can be used multiple times on a page
I hope you like the demo - maybe it will find it's way into one of your projects? If it does, let me know in the comments.