Of late, I have been building some Html/Javascript apps and exploring a bunch of javascript libraries, including the usual suspects (jQuery, jQuery UI, jQuery template, underscore, etc). The more interesting ones are visualization libraries like d3, isotope, highcharts. In this post, I will focus on a specific scenario in the isotope.js library.

Isotope.js is a neat jQuery plugin for doing layout animations and provides a bunch of cool layout modes. When it is applied to a list of items, it lays them out in one of the several layout-modes and animates their positions upon changes in the list. It also provides sorting and filtering hooks which also trigger layout animations when applied. The GIF animation below gives a glimpse of the ‘masonry’ layout mode.

The way isotope treats filters is by looking for a particular CSS class on each of the items. If the item has that class, it is included in the filtered list. This form of filtering is very declarative and easy to apply.

However if you need more complex filtering, you will have to do some leg work. You will have observed in other toolkits, frameworks that filter is generally considered as a lambda-function that will be invoked for each item in the list. This is a convenient form of providing the filtering logic.

Isotope, however does not think that way and only looks at the class attribute of the item and matches on the supplied filter-class-name. This means, we will have to pre-process the items, apply the complex filtering logic and attach an ad-hoc class to the item. That is the key to complex filtering in isotope: a pre-processing step that attaches an ad-hoc class on matched items, which is then used by isotope.

The code-snipped below shows the pre-processing step before invoking the $.isotope() function. Look for the comments starting with [1], [2], [3].

function createTestData ( ) { var people = _ . range ( 0 , 100 ) . map ( function ( p ) { return { name : 'Name-' + p , age : Math . round ( Math . random ( ) * 50 ) , email : 'email-' + p + '@company.com' , image : 'css/ninja/' + Math . ceil ( Math . random ( ) * 6 ) + '.png' , } ; } ) ; $ ( '#person-template' ) . tmpl ( people ) . appendTo ( '#people-list' ) ; $ ( '#people-list' ) . isotope ( { layoutMode : 'masonry' , } ) ; } $ ( document ) . ready ( function ( ) { createTestData ( ) ; function predicate ( data ) { return data . age > 25 ; } $ ( '#invoke' ) . click ( function ( ) { $ ( '.isotope-item' ) . each ( function ( ) { var item = $ ( this ) . tmplItem ( ) . data ; if ( predicate ( item ) ) $ ( this ) . addClass ( 'matched-item' ) ; else $ ( this ) . removeClass ( 'matched-item' ) ; } ) ; $ ( '#people-list' ) . isotope ( { filter : '.matched-item' , } ) ; } ) ; $ ( '#reset' ) . click ( function ( ) { $ ( '.isotope-item' ) . each ( function ( ) { $ ( this ) . removeClass ( 'matched-item' ) ; } ) ; $ ( '#people-list' ) . isotope ( { filter : '*' , } ) ; } ) ; } ) ;

So filtering in isotope can still be done the traditional way, just that we need a pre-processing step.

Demo