For far too long I’ve been writing blog posts with way too much whimsy and outspoken statements about the Industry. Lately I have been much more focused on actually creating useful things. I feel so much more positive about my work these days that I have had the motivation to actually write a Blog post on something I made a while ago for an old colleague.
I should point out that this is quite advanced and some undertsanding of the finer points of HTML/CSS/jQuery are necessary in order to understand every detail. I even had to do quite a few modifications to my code highlighting to handle this, so please bare that in mind. It ain’t easy kids!
I made this a while back now for a small site where they wanted the interface to do all the work. They wanted to have a portfolio of projects they had worked on but had quite a diverse ‘jack of all trades’ category list to work with.
The following information was the kind of thing I had to work with from the start of the project (names of categories are made up to avoid conflicting with the real life project).
Customer list
- Yahoo
- Microsoft
- Geewiz Inc
- Apple
Service list
- Flat Design
- Working Design
- Interaction Design
- Back End Programming
- Writing
- Administration
Year list
- 2011
- 2010
- 2009
- 2008
- 2007
- 2006
- 2005
My brief was to create a ‘filterable list’ where the user would be able to click on each category item in turn to show and hide all the items under that category. I thought this was also a great idea and something I could use in other projects where I could develop the script and behaviour further.
The basics of the request were pretty straight forward to achieve. They basically wanted to be able to click on items and have items within the selected categories appear or disappear accordingly as part of the interface. Things like the jQuery Quicksand plugin or the Filtering Blocks demo quickly sprang to mind until I realised that they were asking for one extra vital component, the ability to select more than one thing at a time. None of these interfaces have the ability to do this and it requires much more thought and script to achieve.
Where the heck to start?!
My first action as with any slightly daunting project was to panic but this was shortlived. I then went about investigating why the above examples acted in the way they did and what the jQuery was interacting with on the page.
Once I started to understand this, I could start putting together some structure. Thankfully, I was working to a predetermined design (which always helps). This was unlikely to change so I knew I could confidently go to town on the jQuery without fear of repercussions further down the line. There are few things less heartening than to do a weeks work on something only for it to be scrapped the following Monday because someone changed their mind.
Panic over, lets begin
The best place to start with any project, if there is a design in place and it has been approved and double approved, build it! The behaviour can always be applied to the finished design so unquestionably, always build something you and the user of the site would be happy to use without any Javascript enhancements. Below is the HTML I ended up with:
The HTML
<!doctype html> <!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]--> <!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]--> <!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]--> <!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]--> <!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]--> <head> <meta charset="utf-8"> <title>jQuery Multiple Filter</title> <!-- Mobile viewport optimized: j.mp/bplateviewport --> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Place favicon.ico & apple-touch-icon.png in the root of your domain and delete these references --> <link rel="shortcut icon" href="favicon.ico"> <link rel="apple-touch-icon" href="apple-touch-icon.png"> <!-- CSS : implied media="all" --> <link rel="stylesheet" href="css/style.css?v=2"> <link href='http://fonts.googleapis.com/css?family=Lora&v2' rel='stylesheet' type='text/css'> <!-- Uncomment if you are specifically targeting less enabled mobile browsers <link rel="stylesheet" media="handheld" href="css/handheld.css?v=2"> --> <!-- All JavaScript at the bottom, except for Modernizr which enables HTML5 elements & feature detects --> <script src="js/libs/modernizr-1.6.min.js"></script> </head> <body> <div id="container" class="entry"> <div id="main"> <div class="gradup"> <div class="onethird plus right"> <h3>Filter</h3> <ul class="filters showall"> <li><input type="checkbox" id="filterIDall" value="all" class="dynamicFilterInput"><label for="filterIDall">Show all</label><span>0</span></li> </ul> <h5>Customer</h5> <ul class="filters"> <li><input type="checkbox" id="filterIDgoogle" value="google" class="dynamicFilterInput"><label for="filterIDgoogle">Google</label><span>0</span></li> <li><input type="checkbox" id="filterIDyahoo" value="yahoo" class="dynamicFilterInput"><label for="filterIDyahoo">Yahoo</label><span>0</span></li> <li><input type="checkbox" id="filterIDmicrosoft" value="microsoft" class="dynamicFilterInput"><label for="filterIDmicrosoft">Microsoft</label><span>0</span></li> <li><input type="checkbox" id="filterIDgeewiz" value="geewiz" class="dynamicFilterInput"><label for="filterIDgeewiz">Geewiz Inc</label><span>0</span></li> <li><input type="checkbox" id="filterIDapple" value="apple" class="dynamicFilterInput"><label for="filterIDgeewiz">Apple</label><span>0</span></li> </ul> <h5>Service</h5> <ul class="filters"> <li><input type="checkbox" id="filterIDflat-design" value="flat-design" class="dynamicFilterInput"><label for="filterIDflat-design">Flat Design</label><span>0</span></li> <li><input type="checkbox" id="filterIDworking-design" value="working-design" class="dynamicFilterInput"><label for="filterIDworking-design">Working Design</label><span>0</span></li> <li><input type="checkbox" id="filterIDinteraction-design" value="interaction-design" class="dynamicFilterInput"><label for="filterIDinteraction-design">Interaction Design</label><span>0</span></li> <li><input type="checkbox" id="filterIDback-end-programming" value="back-end-programming" class="dynamicFilterInput"><label for="filterIDback-end-programming">Back End Coding</label><span>0</span></li> <li><input type="checkbox" id="filterIDwriting" value="writing" class="dynamicFilterInput"><label for="filterIDwriting">Content Writing</label><span>0</span></li> <li><input type="checkbox" id="filterIDadministration" value="administration" class="dynamicFilterInput"><label for="filterIDwriting">Administration</label><span>0</span></li> </ul> <h5>Year</h5> <ul class="filters"> <li><input type="checkbox" id="filterID2011" value="2011" class="dynamicFilterInput"><label for="filterID2011">2011</label><span>0</span></li> <li><input type="checkbox" id="filterID2010" value="2010" class="dynamicFilterInput"><label for="filterID2010">2010</label><span>0</span></li> <li><input type="checkbox" id="filterID2009" value="2009" class="dynamicFilterInput"><label for="filterID2009">2009</label><span>0</span></li> <li><input type="checkbox" id="filterID2008" value="2008" class="dynamicFilterInput"><label for="filterID2008">2008</label><span>0</span></li> <li><input type="checkbox" id="filterID2007" value="2007" class="dynamicFilterInput"><label for="filterID2007">2007</label><span>0</span></li> <li><input type="checkbox" id="filterID2006" value="2006" class="dynamicFilterInput"><label for="filterID2006">2006</label><span>0</span></li> <li><input type="checkbox" id="filterID2005" value="2005" class="dynamicFilterInput"><label for="filterID2005">2005</label><span>0</span></li> </ul> <div class="filterThis"></div> </div> <div class="twothird plus left"> <h2>Projects completed</h2> <div id="post-12" class="post-12 page type-page status-publish hentry"> <div class="entry-made played"> <p>Whoah! Thats a big fat Nullity. Try clicking a few more boxes ...</p> </div> </div> <div class="entry-made"> <ul id="holder-init" class="filterThis showThis"> <li class=" 2011 working-design microsoft flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Microsoft Homepage</a></h3> </div> </li> <li class=" 2011 working-design microsoft flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Windows Promotion</a></h3> </div> </li> <li class=" 2010 working-design yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Re-design of YUI</a></h3> </div> </li> </ul> </div><!-- .entry-content --> <div id="holderwrap"> <ul id="holder" class="filterThis"> <li class=" 2011 working-design microsoft flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Microsoft Homepage</a></h3> </div> </li> <li class=" 2011 working-design microsoft flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Windows Promotion</a></h3> </div> </li> <li class=" 2010 working-design yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Re-design of YUI</a></h3> </div> </li> <li class=" 2010 back-end-programming microsoft flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Windows 7</a></h3> </div> </li> <li class=" 2010 yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">YQL Interface</a></h3> </div> </li> <li class=" 2010 yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Yahoo Blog</a></h3> </div> </li> <li class=" 2010 yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Front End Development leaflet</a></h3> </div> </li> <li class=" 2010 administration yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">HTML File System</a></h3> </div> </li> <li class=" 2010 yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Yahoo Answers</a></h3> </div> </li> <li class=" 2009 interaction-design yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Yahoo Mail</a></h3> </div> </li> <li class=" 2010 yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Yahoo Weather</a></h3> </div> </li> <li class=" 2009 writing design interaction-design geewiz flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Transition Munition</a></h3> </div> </li> <li class=" 2009 yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Yahoo UK</a></h3> </div> </li> <li class=" 2009 writing administration microsoft interaction-design flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">IE6 Downfall</a></h3> </div> </li> <li class=" 2008 back-end-programming interaction-design yahoo"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Sustainable Development Organisation</a></h3> </div> </li> <li class=" 2005 writing interaction-design yahoo"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Blog Post</a></h3> </div> </li> <li class=" 2008 yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Presentation Slides</a></h3> </div> </li> <li class=" 2009 interaction-design yahoo flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Click Through Presentation</a></h3> </div> </li> <li class=" 2008 flat-design interaction-design yahoo"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Interface Components</a></h3> </div> </li> <li class=" 2008 working-design google"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Google +</a></h3> </div> </li> <li class=" 2008 interaction-design microsoft"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Windows Phone</a></h3> </div> </li> <li class=" 2008 interaction-design google"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Touchscreen Interface</a></h3> </div> </li> <li class=" 2008 apple google"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Merger Talks</a></h3> </div> </li> <li class=" 2008 administration apple"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Market Saturation Enquiry</a></h3> </div> </li> <li class=" 2007 flat-design google"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Google -</a></h3> </div> </li> <li class=" 2006 working-design microsoft interaction-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Microsoft Site</a></h3> </div> </li> <li class=" 2006 geewiz flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Quick Update</a></h3> </div> </li> <li class=" 2006 writing working-design microsoft interaction-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Company Progress Report</a></h3> </div> </li> <li class=" 2006 geewiz working-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="">Screenshot with iPhone</a></h3> </div> </li> <li class=" 2006 geewiz interaction-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Fixing Interface</a></h3> </div> </li> <li class=" 2006 writing geewiz"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Blog Post</a></h3> </div> </li> <li class=" 2006 geewiz administration"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Version Control</a></h3> </div> </li> <li class=" 2005 geewiz flat-design"> <a href="http://www.webegg.co.uk"><img src="images/testimage-smaller.jpg" alt="blog post" /></a> <div class="caption"> <h3><a href="http://www.webegg.co.uk">Re-design on a Budget</a></h3> </div> </li> </ul> </div> </div> <div class="clearboth"></div> </div> </div> <!-- Grab Google CDN's jQuery. fall back to local if necessary --> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script> <script>!window.jQuery && document.write(unescape('%3Cscript src="js/libs/jquery-1.4.2.js"%3E%3C/script%3E'))</script> <!-- scripts concatenated and minified via ant build script--> <script src="js/plugins.js"></script> <script src="js/script.js"></script> </body> </html>
The main elements here are the
.filter li
‘s and the
#holder li
‘s. In order for the two to talk to each other, they have to have something in common. In this instance it is done with classes. In this instance I have used
elements to trigger a click event. This is purely because the design had checkboxes shown and it was better to tie the click event to something that was easy to reference checked or unchecked. This could just as easily be done with other elements, adding and removing classes and checking for the presence of them.
When a click is made on these elements, the jQuery runs through a series of thought out procedures:
- If the ‘Show all’ checkbox has been clicked
- If it is and it is checked, make all projects appear
- If it is and its not checked, make all projects disappear
- If not, is the selection checked
- If its checked, we must need to show all the elements with the same class as the value in the checkbox input. We need to show all the elements that match the selection, then make an array out of all the categories matching the selection. Then they are checked in the filter list to show the user what other categories share the project.
- If it got as far as this, the only possibility left is that something is being deselected. We need to hide all the elements that match the selection, then make an array out of all the categories matching the selection. Then they are deselected from the filter list.
I told you it was quite in depth and I have done my best to explain things. It may help if I actually show you the script.js file for it:
The jQuery
$(document).ready(function () { // Removes all filtered elements initially $("#holder li, .played").hide(); $("#holder.showThis li").show(); // Counts up occurances of classes and sets number of occurrences in filter list $(".filters li").each(function(){ var $val = $(this).find('input').val(); var $valcount = $("#holder ."+$val).length; $(this).find('span').html($valcount); //alert($valcount); }); // Sets the number in the 'Show all' filter by counting the total amount of entries. var $itval = $("#holder li").length; $(".filters li input[value*='all']").parent().find('span').html($itval); // When clicking an item in the filter list, elements will appear or dissappear // depending on whether list item is checked or unchecked. $(".filters li input[type=checkbox]").click(function(){ $('a.jqTransformCheckbox').parent().find('input[type=checkbox]').removeAttr('checked'); $('a.jqTransformChecked').parent().find('input[type=checkbox]').attr('checked','checked'); // next two lines remove the initial page content when a filter is clicked $(".entry-made").hide(); $(".entry-written").hide(); var selection = $(this).val(); if (selection == "all"){ //show all items if ($(this).is(':checked')){ $("#holder li img").fadeIn('fast'); $("#holder li").slideDown('slow'); $(".filters li input[type=checkbox]").attr('checked','checked'); $(".filters li").addClass('checked'); $(".filters li label").css({'color':'#efefef'}); }else{ $("#holder li img").fadeOut('slow'); $("#holder li").slideUp('slow', function() { $(".played").slideDown('fast'); }); $(".filters li input[type=checkbox]").removeAttr('checked'); $(".filters li").removeClass('checked'); $(".filters li label").css({'color':'#40575F'}); } }else{ if ($(this).is(':checked')){ $("#holder li."+selection+" img").fadeIn('slow'); $("#holder li."+selection).prependTo('#holder').slideDown('fast'); var stringOfClassNames = ''; var thisClassString = $("#holder li."+selection).attr('class'); stringOfClassNames = stringOfClassNames +' '+ thisClassString; var arrayClasses = stringOfClassNames.split(' '); $.each(arrayClasses, function() { $('.filters input[value='+this+']').parent('li').addClass('checked'); $('.filters input[value='+this+']').parent('li').find('label').css({'color':'#efefef'}); $('.filters input[value='+this+']').attr('checked','checked'); }); $(this).parent('li').addClass('checked'); $(this).parent().find('label').css({'color':'#efefef'}); if ($.browser.webkit) { $('#main #holder li').css({'position':'relative'}) } }else{ $("#holder li."+selection+" img").fadeOut('slow'); $("#holder li."+selection).slideUp('fast', function() { var stringOfClassNames = ''; var thisClassString = $("#holder li."+selection).attr('class'); stringOfClassNames = stringOfClassNames +' '+ thisClassString; var arrayClasses = stringOfClassNames.split(' '); $.each(arrayClasses, function() { $('.filters input[value='+this+']').parent('li').removeClass('checked'); $('.filters input[value='+this+']').parent().find('a.jqTransformCheckbox').removeClass('jqTransformChecked'); $('.filters input[value='+this+']').parent('li').find('label').css({'color':'#40575F'}); $('.filters input[value='+this+']').removeAttr('checked'); }); if ($('.filters input:checked').length <= 0){ $("#holder li").slideUp('fast'); $(".played").slideDown('fast'); } }); $(this).parent('li').removeClass('checked'); $(this).parent('li.'+selection+' input[type=checkbox]').removeAttr('checked'); $(this).parent().find('label').css({'color':'#40575F'}); if ($('#filterIDall').is(':checked')){ $('#filterIDall').removeAttr('checked'); $('#filterIDall').parent().find('li').removeClass('checked'); $('#filterIDall').parent().find('label').css({'color':'#40575F'}); } } } }); });
In conclusion, this is a great bit of Interface Design that I’m quite proud of. I do know there are a few slight improvements possible and I’m open to any comments but hope someone out there finds it helpful.
seb
wohooo, thats so awesome! just what i needed. blog bookmarked.
luca
This is AWESOMEEEEEE!!!!! very well done.
I have a question. Do you think is possible to call the list from a DB and achieve the same result and have a lighter script?
Webegg
Hi Luca. I guess you mean with Ajax. I can’t see a reason why you couldn’t adapt the script to work with Ajax calls rather than everything on the page. It’d be great to see it inspire something else.
counterstrike global offensive
My brother suggested I might like this web site. He was once entirely right. This put up truly made my day. You can not believe just how so much time I had spent for this information! Thanks!