Search and Filter items in grid layout with isotop javascript library
I want to create a portfolio page that listing all of my projects with search and filter functionalities. I search through a lot of javascript libraries and isotope is the only one that I can make it to work (I tried Filterizr, it worked, but if the number of items is about 100, everything will be broken):
Isotope official page: http://isotope.metafizzy.co/
This is a working example. It's easy, just read through the code and you will understand:
The code's below:
Isotope official page: http://isotope.metafizzy.co/
This is a working example. It's easy, just read through the code and you will understand:
Isotope - filtering with search field and button filters
The code's below:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> | |
<script src="https://unpkg.com/isotope-layout@3.0/dist/isotope.pkgd.js"></script> | |
<style> | |
* { box-sizing: border-box; } | |
body { | |
font-family: sans-serif; | |
} | |
/* ---- input ---- */ | |
input[type="text"] { | |
font-size: 20px; | |
} | |
/* ---- button ---- */ | |
.button { | |
display: inline-block; | |
padding: 0.5em 1.0em; | |
margin-bottom: 10px; | |
background: #EEE; | |
border: none; | |
border-radius: 7px; | |
background-image: linear-gradient( to bottom, hsla(0, 0%, 0%, 0), hsla(0, 0%, 0%, 0.2) ); | |
color: #222; | |
font-family: sans-serif; | |
font-size: 16px; | |
text-shadow: 0 1px white; | |
cursor: pointer; | |
} | |
.button:hover { | |
background-color: #8CF; | |
text-shadow: 0 1px hsla(0, 0%, 100%, 0.5); | |
color: #222; | |
} | |
.button:active, | |
.button.is-checked { | |
background-color: #28F; | |
} | |
.button.is-checked { | |
color: white; | |
text-shadow: 0 -1px hsla(0, 0%, 0%, 0.8); | |
} | |
.button:active { | |
box-shadow: inset 0 1px 10px hsla(0, 0%, 0%, 0.8); | |
} | |
/* ---- button-group ---- */ | |
.button-group:after { | |
content: ''; | |
display: block; | |
clear: both; | |
} | |
.button-group .button { | |
float: left; | |
border-radius: 0; | |
margin-left: 0; | |
margin-right: 1px; | |
} | |
.button-group .button:first-child { border-radius: 0.5em 0 0 0.5em; } | |
.button-group .button:last-child { border-radius: 0 0.5em 0.5em 0; } | |
/* ---- grid ---- */ | |
.grid { | |
border: 1px solid #333; | |
} | |
/* clear fix */ | |
.grid:after { | |
content: ''; | |
display: block; | |
clear: both; | |
} | |
/* ---- .element-item ---- */ | |
.element-item { | |
position: relative; | |
float: left; | |
width: 100px; | |
height: 100px; | |
margin: 5px; | |
padding: 10px; | |
background: #888; | |
color: #262524; | |
} | |
.element-item > * { | |
margin: 0; | |
padding: 0; | |
} | |
.element-item .name { | |
position: absolute; | |
left: 10px; | |
top: 60px; | |
text-transform: none; | |
letter-spacing: 0; | |
font-size: 12px; | |
font-weight: normal; | |
} | |
.element-item .symbol { | |
position: absolute; | |
left: 10px; | |
top: 0px; | |
font-size: 42px; | |
font-weight: bold; | |
color: white; | |
} | |
.element-item .number { | |
position: absolute; | |
right: 8px; | |
top: 5px; | |
} | |
.element-item .weight { | |
position: absolute; | |
left: 10px; | |
top: 76px; | |
font-size: 12px; | |
} | |
.element-item.alkali { background: #F00; background: hsl( 0, 100%, 50%); } | |
.element-item.alkaline-earth { background: #F80; background: hsl( 36, 100%, 50%); } | |
.element-item.lanthanoid { background: #FF0; background: hsl( 72, 100%, 50%); } | |
.element-item.actinoid { background: #0F0; background: hsl( 108, 100%, 50%); } | |
.element-item.transition { background: #0F8; background: hsl( 144, 100%, 50%); } | |
.element-item.post-transition { background: #0FF; background: hsl( 180, 100%, 50%); } | |
.element-item.metalloid { background: #08F; background: hsl( 216, 100%, 50%); } | |
.element-item.diatomic { background: #00F; background: hsl( 252, 100%, 50%); } | |
.element-item.halogen { background: #F0F; background: hsl( 288, 100%, 50%); } | |
.element-item.noble-gas { background: #F08; background: hsl( 324, 100%, 50%); } | |
</style> | |
<h1>Isotope - filtering with search field and button filters</h1> | |
<p><input type="text" id="quicksearch" placeholder="Search" /></p> | |
<div id="filters" class="button-group"> | |
<button class="button is-checked" data-filter="*">show all</button> | |
<button class="button" data-filter=".metal">metal</button> | |
<button class="button" data-filter=".transition">transition</button> | |
<button class="button" data-filter=".alkali, .alkaline-earth">alkali and alkaline-earth</button> | |
<button class="button" data-filter=":not(.transition)">not transition</button> | |
<button class="button" data-filter=".metal:not(.transition)">metal but not transition</button> | |
</div> | |
<div class="grid"> | |
<div class="element-item transition metal " data-category="transition"> | |
<h3 class="name">Mercury</h3> | |
<p class="symbol">Hg</p> | |
<p class="number">80</p> | |
<p class="weight">200.59</p> | |
</div> | |
<div class="element-item metalloid " data-category="metalloid"> | |
<h3 class="name">Tellurium</h3> | |
<p class="symbol">Te</p> | |
<p class="number">52</p> | |
<p class="weight">127.6</p> | |
</div> | |
<div class="element-item post-transition metal " data-category="post-transition"> | |
<h3 class="name">Bismuth</h3> | |
<p class="symbol">Bi</p> | |
<p class="number">83</p> | |
<p class="weight">208.980</p> | |
</div> | |
<div class="element-item post-transition metal " data-category="post-transition"> | |
<h3 class="name">Lead</h3> | |
<p class="symbol">Pb</p> | |
<p class="number">82</p> | |
<p class="weight">207.2</p> | |
</div> | |
<div class="element-item transition metal " data-category="transition"> | |
<h3 class="name">Gold</h3> | |
<p class="symbol">Au</p> | |
<p class="number">79</p> | |
<p class="weight">196.967</p> | |
</div> | |
<div class="element-item alkali metal " data-category="alkali"> | |
<h3 class="name">Potassium</h3> | |
<p class="symbol">K</p> | |
<p class="number">19</p> | |
<p class="weight">39.0983</p> | |
</div> | |
<div class="element-item alkali metal " data-category="alkali"> | |
<h3 class="name">Sodium</h3> | |
<p class="symbol">Na</p> | |
<p class="number">11</p> | |
<p class="weight">22.99</p> | |
</div> | |
<div class="element-item transition metal " data-category="transition"> | |
<h3 class="name">Cadmium</h3> | |
<p class="symbol">Cd</p> | |
<p class="number">48</p> | |
<p class="weight">112.411</p> | |
</div> | |
<div class="element-item alkaline-earth metal " data-category="alkaline-earth"> | |
<h3 class="name">Calcium</h3> | |
<p class="symbol">Ca</p> | |
<p class="number">20</p> | |
<p class="weight">40.078</p> | |
</div> | |
<div class="element-item transition metal " data-category="transition"> | |
<h3 class="name">Rhenium</h3> | |
<p class="symbol">Re</p> | |
<p class="number">75</p> | |
<p class="weight">186.207</p> | |
</div> | |
<div class="element-item post-transition metal " data-category="post-transition"> | |
<h3 class="name">Thallium</h3> | |
<p class="symbol">Tl</p> | |
<p class="number">81</p> | |
<p class="weight">204.383</p> | |
</div> | |
<div class="element-item metalloid " data-category="metalloid"> | |
<h3 class="name">Antimony</h3> | |
<p class="symbol">Sb</p> | |
<p class="number">51</p> | |
<p class="weight">121.76</p> | |
</div> | |
<div class="element-item transition metal " data-category="transition"> | |
<h3 class="name">Cobalt</h3> | |
<p class="symbol">Co</p> | |
<p class="number">27</p> | |
<p class="weight">58.933</p> | |
</div> | |
<div class="element-item lanthanoid metal inner-transition " data-category="lanthanoid"> | |
<h3 class="name">Ytterbium</h3> | |
<p class="symbol">Yb</p> | |
<p class="number">70</p> | |
<p class="weight">173.054</p> | |
</div> | |
<div class="element-item noble-gas nonmetal " data-category="noble-gas"> | |
<h3 class="name">Argon</h3> | |
<p class="symbol">Ar</p> | |
<p class="number">18</p> | |
<p class="weight">39.948</p> | |
</div> | |
<div class="element-item diatomic nonmetal " data-category="diatomic"> | |
<h3 class="name">Nitrogen</h3> | |
<p class="symbol">N</p> | |
<p class="number">7</p> | |
<p class="weight">14.007</p> | |
</div> | |
<div class="element-item actinoid metal inner-transition " data-category="actinoid"> | |
<h3 class="name">Uranium</h3> | |
<p class="symbol">U</p> | |
<p class="number">92</p> | |
<p class="weight">238.029</p> | |
</div> | |
<div class="element-item actinoid metal inner-transition " data-category="actinoid"> | |
<h3 class="name">Plutonium</h3> | |
<p class="symbol">Pu</p> | |
<p class="number">94</p> | |
<p class="weight">(244)</p> | |
</div> | |
</div> | |
<script> | |
// quick search regex | |
var qsRegex; | |
var buttonFilter; | |
// init Isotope | |
var $grid = $('.grid').isotope({ | |
itemSelector: '.element-item', | |
layoutMode: 'fitRows', | |
filter: function() { | |
var $this = $(this); | |
var searchResult = qsRegex ? $this.text().match( qsRegex ) : true; | |
var buttonResult = buttonFilter ? $this.is( buttonFilter ) : true; | |
return searchResult && buttonResult; | |
} | |
}); | |
$('#filters').on( 'click', 'button', function() { | |
buttonFilter = $( this ).attr('data-filter'); | |
$grid.isotope(); | |
}); | |
// use value of search field to filter | |
var $quicksearch = $('#quicksearch').keyup( debounce( function() { | |
qsRegex = new RegExp( $quicksearch.val(), 'gi' ); | |
$grid.isotope(); | |
}) ); | |
// change is-checked class on buttons | |
$('.button-group').each( function( i, buttonGroup ) { | |
var $buttonGroup = $( buttonGroup ); | |
$buttonGroup.on( 'click', 'button', function() { | |
$buttonGroup.find('.is-checked').removeClass('is-checked'); | |
$( this ).addClass('is-checked'); | |
}); | |
}); | |
// debounce so filtering doesn't happen every millisecond | |
function debounce( fn, threshold ) { | |
var timeout; | |
return function debounced() { | |
if ( timeout ) { | |
clearTimeout( timeout ); | |
} | |
function delayed() { | |
fn(); | |
timeout = null; | |
} | |
setTimeout( delayed, threshold || 100 ); | |
}; | |
} | |
</script> |