Reputation: 25
I have a page where I want the user to be able to filter on a number of different classes at the same time. Currently, I'm using the following to allow them to filter on just 1 class at a time:
$(document).ready(function(){
$(".filter-button").click(function(){
var value = $(this).attr('data-filter');
if(value == "all")
{
$('.filter').show('1000');
}
else
{
$(".filter").not('.'+value).hide('3000');
$('.filter').filter('.'+value).show('3000');
}
});
});
So let's say there is a list of animals and I want to find all orange cats. Currently I could only find either all cats or all orange animals, not combine the two to find just orange cats.
EDIT: Here is a Fiddle example of what I currently have. What I'm looking for is to be able to click Cats, then Orange, and have it only show "Orange Cat".
EDIT 2 (SOLVED): Me.Name's answer provided the solution I needed. I have refined it slightly further to allow the buttons to toggle on and off (supports more than 2 filters) - Fiddle.
Upvotes: 1
Views: 3882
Reputation: 12544
edit Based on the updated question, I had the goal reversed in the original answer, (and some quick edits inbetween other chores didn't fare quite well :D), but the same principle can be used: create a selector based on the combined classes. Perhaps checkboxes would be better, but by using the buttons and a an extra 'checked' class:
$(document).ready(function(){
var targets = $('.filter'),
buttons = $('.filter-button').click(function(){
var value = $(this).data('filter');
if(value == "all")
buttons.removeClass('checked');
else
$(this).toggleClass('checked');
var checkedClasses = buttons.filter('.checked').toArray().map(function(btn){return $(btn).data('filter');}); //create array of filters
if(checkedClasses.length === 0)
targets.show('1000');
else
{
var selector = '.' + checkedClasses.join('.'), //create selector of the combined classes
show = targets.filter(selector);
targets.not(show).hide('3000');
show.show('3000');
}
});
});
.checked{
font-style: italic;
background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<button class="filter-button" type="button" data-filter="all">Show All</button>
<button class="filter-button" type="button" data-filter="cat">Cats</button>
<button class="filter-button" type="button" data-filter="orange">Orange</button>
</div>
<div>
<p class="filter cat">Cat</p>
<p class="filter orange">Orange</p>
<p class="filter cat orange">Orange Cat</p>
<p class="filter cat pink">Pink panther</p>
</div>
Orignal answer (for filtering on more properties):
You could place all values inside the 'data-filter' attributes and parse them to a selector, but to make life easier, you could also place the entire (jQuery) selector inside the attribute.
So instead of data-filter = 'orange'
, use data-filter = '.orange'
and for 2: data-filter= '.orange,.animal'
Of course, the extra dot should not be added inside the handler then, but used directly, e.g. $(".filter").not(value)
Example:
$(function(){
var targets = $('.filter');
$('.filter-all').click(function(){ targets.show(1000); }); //put the 'all' in a separate class with seperate handler to prevent the if, but that's just a preference
$('.filter-button').click(function(){
var selector = $(this).data('filter');
targets.not(selector).hide('3000');
targets.filter(selector).show('3000');
});
})
.filter{
border:1px solid blue;
background-color:lightblue;
height:50px;
text-align:center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class='filter-all' data-filter= 'all'>All</button>
<button class='filter-button' data-filter= '.d1'>1</button>
<button class='filter-button' data-filter= '.d2'>2</button>
<button class='filter-button' data-filter= '.d3'>3</button>
<button class='filter-button' data-filter= '.d1,.d3'>1 + 3</button>
<div class='d1 filter'>1</div>
<div class='d2 filter'>2</div>
<div class='d3 filter'>3</div>
Upvotes: 1
Reputation:
Here we go!
Firstly we create an array of filters, so that - regardless of the number of items that are added to the list - we are always going to have an appropriate amount of buttons.
// Create an array of filters
var filtersArray = [];
// Retrieve all the possible filters from the DOM
$(".filter").each(function(){
var classes = $(this).attr("class").split(" ");
classes.forEach(function(e) {filtersArray.push(e.toString());});
});
// Select only unique values, remove empty values and take away the "filter" class, since it's not a real filter
var filtersUnique = filtersArray.filter(function(el,i) {return i ==
filtersArray.indexOf(el);});
var filtersEmpty = filtersUnique.filter(function(v){return v!==''});
var filters = filtersEmpty.filter(function(v){return v!=='filter'});
// Create a button for each filter
$.each(filters,function(k,v){
$(".filters").append('<button class="filter-button" type="button" data-filter="'+v+'">'+v+'</button>');
});
The click function itself hides all elements that do not have the specific class.
// Click Function
$(".filter-button").click(function(){
var dataFilter = $(this).attr("data-filter");
var dataFilterClass = ("."+dataFilter);
$(".filter").not(dataFilterClass).addClass("hidden");
});
Edit. Forgot Jsfiddle: https://jsfiddle.net/uaf5rLdt/
It would be nice to add some logic to hide the buttons that are not useful anymore (e.g. "Horse" and "Dog", whenever an user clicks on "Cat").
Upvotes: 0
Reputation: 10179
Here is the code that working for you:
Update you html, add data filter with "." too:
$(document).ready(function() {
$(".filter-button").click(function() {
$(this).toggleClass('active')
var value = $(this).attr('data-filter');
var active = $(this).hasClass('active');
$('.filter').hide();
if (value == "all" && active) {
$('.filter').show('1000');
return;
}
$(".filter-button.all").removeClass('active')
var cFilter = "";
$('.filter-button.active').each(function() {
cFilter += "." + $(this).attr('data-filter');
});
$('p.filter').filter(cFilter).show('3000');
});
});
.active {
border-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<body>
<div>
<button class="filter-button all" type="button" data-filter="all">Show All</button>
<button class="filter-button" type="button" data-filter="cat">Cats</button>
<button class="filter-button" type="button" data-filter="orange">Orange</button>
</div>
<div>
<p class="filter cat">Cat</p>
<p class="filter orange">Orange</p>
<p class="filter cat orange">Orange Cat</p>
</div>
</body>
Upvotes: 0