Reputation: 426
I'm trying to filter through users by selecting multiple filters.
The thing is, I'm working with third party software which shows my user list in multiple tables. So each user does have unique ID but also each user is in several tables so I'm trying to filter through them.
So, for example, if you checkmark color Blue and item Bucket, it should display only users that have both of those classes.
I'm trying to use $(this).val() to get the name of the value of the checkbox and search it as class in each user, so if those two classes (or more) match with each user, it should show them in the showUsers results bellow.
I've setup example and my failed attempt at this: JSFiddle
HTML
<!-- FILTERS -->
<h3>Filter items</h3>
<div class="filter-list-one">
<input type="checkbox" value="Wood">Wood<br>
<input type="checkbox" value="Bucket">Bucket<br>
<input type="checkbox" value="Hammer">Hammer<br>
</div>
<h3>Filter colors</h3>
<div class="filter-list-two">
<input type="checkbox" value="Red">Red<br>
<input type="checkbox" value="Purple">Purple<br>
<input type="checkbox" value="Blue">Blue<br>
</div>
<!-- FILTERS END -->
<!-- SEARCHING THROUGH -->
<h3>Results</h3>
<div class="objects">
<p id="user1" class="user">
<span>wood</span>
<span class="bucket">bucket</span>
<span>hammer</span>
</p>
<p id="user2" class="user">
<span>wood</span>
<span class="bucket">bucket</span>
<span class="bucket">hammer</span>
</p>
<p id="user3" class="user">
<span class="bucket"n>wood</span>
<span class="bucket">bucket</span>
<span>hammer</span>
</p>
</div>
<div class="colors">
<p id="user1">
<span>red</span>
<span class="purple">purple</span>
<span>blue</span>
</p>
<p id="user2">
<span class="purple">red</span>
<span>purple</span>
<span>blue</span>
</p>
<p id="user3">
<span>red</span>
<span class="purple">purple</span>
<span class="purple">blue</span>
</p>
</div>
<div class="showUsers">
<div id="user1" class="filtered">I'm here and I have those things</div>
<div id="user2" class="filtered">I'm here and I have those things</div>
<div id="user3" class="filtered">I'm here and I have those things</div>
</div>
<!-- SEARCHING THROUGH NED -->
CSS
div {
margin-bottom: 20px;
}
h3 {
margin: 5px 0;
}
p {
margin: 0 5px;
}
.colors p,
.user,
.filtered {
display: none;
}
jQuery
$(".filter-list-one :checkbox, .filter-list-two :checkbox").change(function() {
if ( ($(".items" + $(this).val())[0]) && ($(".colors" + $(this).val())[0]) ) {
var showUser = $(this).closest(".user").attr("id");
$(".showUsers").find("#" + horaInicial).css("display, block");
}
});
Upvotes: 0
Views: 1693
Reputation: 3293
Here's some code that runs after the user clicks on any checkbox. It gathers the checked filters and then cycles through each user index and ensures that all are matched before appending them to a list at the bottom.
You shouldn't have multiple elements with the same id
, I have moved the user index into it's own parameter and wrapped the filter options in a div with a filter-group
attribute. This way we can make sure the user no only matches the correct term, but also in the correct context.
This technique will let you add as many different filter groups as you want, without changing the code. The code cannot cope with filter-groups within filter-groups (i.e. nested).
// Add change event to all checkboxes
$(document).on('change', '[filter-group] input[type="checkbox"]', function() {
// Clear users
$("#showUsers").html("");
// Prepare array for filter terms
var filterTerms = [];
var filterGroup = [];
// Cycle through each checked checkbox
$("[filter-group] input[type='checkbox']:checked").each(function() {
// Push value into filter array
filterTerms.push($(this).val().toUpperCase());
// Push filter group into array
filterGroup.push($(this).closest("[filter-group]").attr("filter-group"));
});
// Cycle through each user
$("*[user]").each(function() {
// Get user index, number of filters being applied and setup variable for the number of matched terms
var userIndex = $(this).attr("user");
var filterCount = filterTerms.length;
var filtersMatched = 0;
// Exit early if the user has already been matched
if ($("#showUsers *[user='" + userIndex +"']").length > 0) {
return;
}
// Cycle through filter array
for (var i = 0; i < filterCount; i++) {
// Cycle through each element tagged with user index
$("[user='" + userIndex + "']").each(function() {
// Get search term
var textToSearch = $(this).text().toUpperCase();
// Check if term found
if (textToSearch.indexOf(filterTerms[i]) > -1) {
filtersMatched = filtersMatched + 1;
return;
}
});
}
// If the number of matched terms equals the number of terms
// Replace with the following line if you want ANY filter to be matched
// if ( filtersMatched > 0) {
if ( filtersMatched == filterCount) {
// Append user to list
$("#showUsers").append("<li user='" + userIndex + "'>User " + userIndex + "</li>");
}
});
});
div {
margin-bottom: 20px;
}
h3 {
margin: 5px 0;
}
p {
margin: 0 5px;
}
.colors p,
.user,
.filtered {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- FILTERS -->
<h3>Filter items</h3>
<div class="filter-list filter-list-one" filter-group="object">
<input type="checkbox" value="Wood">Wood<br>
<input type="checkbox" value="Bucket">Bucket<br>
<input type="checkbox" value="Hammer">Hammer<br>
</div>
<h3>Filter colors</h3>
<div class="filter-list filter-list-two" filter-group="color">
<input type="checkbox" value="Red">Red<br>
<input type="checkbox" value="Purple">Purple<br>
<input type="checkbox" value="Blue">Blue<br>
</div>
<!-- FILTERS END -->
<!-- SEARCHING THROUGH -->
<h3>Results</h3>
<div filter-group="objects">
<p user="1">
<span>wood</span>
<span class="bucket">bucket</span>
<span>hammer</span>
</p>
<p user="2">
<span>wood</span>
<span class="bucket">bucket</span>
<span class="bucket">hammer</span>
</p>
<p user="3">
<span class="bucket" n>wood</span>
<span class="bucket">bucket</span>
<span>hammer</span>
</p>
</div>
<div filter-group="colors">
<p user="1">
<span>red</span>
<span>blue</span>
</p>
<p user="2">
<span class="purple">red</span>
<span>purple</span>
</p>
<p user="3">
<span>red</span>
<span class="purple">purple</span>
</p>
</div>
<ul id="showUsers">
</ul>
Upvotes: 1
Reputation: 33933
I think I got what you try to do here...
But you miss many aspects of what your script has to perform in order to "filter" some results based on the data (elements in the page) you wish to use.
First, an id
must be unique. You can't use id="user1
more than once. So I changed it to a data-
attribute.
Then, on each change event, $(this).val()
is the value of the changed element only. You have to store what was previouly checked... And also be sure it is checked! The change
event may fired when the user uncheks it!
So here is an example showing the logical steps... There could be a shorter code to achieve the same result, but since your markup was a bit messy, I didn't try to make it perfectly optimised.
It is still buggy... But I think it's a good starter. Good luck!
console.clear();
var checked = [];
$(".filter-list-one :checkbox, .filter-list-two :checkbox").change(function() {
$(".filtered").hide();
var possible = [];
var confirmed = [];
if($(this).is(":checked")){
checked.push($(this).val());
console.log(checked);
checked.forEach(function(value,index){
var target = checked[index].toLowerCase();
$(".objects .user").each(function(){
if( $(this).find("."+target).length>0 ){
possible.push($(this).data("user"));
}
});
$(".colors .user").each(function(){
if( $(this).find("."+target).length>0 && $.inArray($(this).data("user"),possible)!=-1 ){
confirmed.push($(this).data("user"));
}
});
});
console.log("possible: "+possible);
console.log("confirmed: "+confirmed)
confirmed.forEach(function(value,index){
$(".filtered[data-user='"+value+"']").show();
});
}else{ // If unchecking...
console.log("unchecking "+$(this).val());
if($.inArray($(this).val(),checked)!=-1){
checked.splice($.inArray($(this).val()),1);
console.log(checked)
}
}
});
div {
margin-bottom: 20px;
}
h3 {
margin: 5px 0;
}
p {
margin: 0 5px;
}
.colors p,
.user,
.filtered {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- FILTERS -->
<h3>Filter items</h3>
<div class="filter-list-one">
<input type="checkbox" value="Wood">Wood<br>
<input type="checkbox" value="Bucket">Bucket<br>
<input type="checkbox" value="Hammer">Hammer<br>
</div>
<h3>Filter colors</h3>
<div class="filter-list-two">
<input type="checkbox" value="Red">Red<br>
<input type="checkbox" value="Purple">Purple<br>
<input type="checkbox" value="Blue">Blue<br>
</div>
<!-- FILTERS END -->
<!-- SEARCHING THROUGH -->
<h3>Results</h3>
<div class="objects">
<p data-user="user1" class="user">
<span class="wood">wood</span>
</p>
<p data-user="user2" class="user">
<span class="bucket">bucket</span>
</p>
<p data-user="user3" class="user">
<span class="hammer">hammer</span>
</p>
</div>
<div class="colors">
<p data-user="user1" class="user">
<span class="red">red</span>
</p>
<p data-user="user2" class="user">
<span class="purple">purple</span>
</p>
<p data-user="user3" class="user">
<span class="blue">blue</span>
</p>
</div>
<div class="showUsers">
<div data-user="user1" class="filtered">I'm USER #1 and I have those things</div>
<div data-user="user2" class="filtered">I'm USER #2 and I have those things</div>
<div data-user="user3" class="filtered">I'm USER #3 and I have those things</div>
</div>
<!-- SEARCHING THROUGH NED -->
Upvotes: 1