0

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");

}

});
3
  • what do you mean by the if statement? what are you expecting from this ($(".items" + $(this).val())[0]) ? Commented Dec 25, 2018 at 16:32
  • I'm trying to get the value of the checked item and search it as a class in colors and objects containers. Commented Dec 25, 2018 at 17:05
  • but there are no classes start with .items ?! Commented Dec 25, 2018 at 17:13

2 Answers 2

1

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).


Demonstration

// 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>

Sign up to request clarification or add additional context in comments.

5 Comments

Just one thing, can I also display users with only one filter checked?
Sure! Change the line: if ( filtersMatched == filterCount) to if ( filtersMatched > 0 ) if you want to display anything that matches at least one filter
Ahhh I see what's wrong, it looks like it filters with OR, but it should filter them with AND. What I mean is, if you choose Blue, it should show all the users that have Blue (in this example, only User1), but if you select Blue and Wood, it should still show only User1 and if you would add Purple as well, there would be no Users left to show (because no users has all three words). Btw can I somehow send you like $20 somewhere? This is such an awesome script, you really helped a lot :)
Looks like it's working exactly like that to me...? Maybe I'm misunderstanding... the code above effectively uses AND to ensure all filter elements are matched. If you wanted to use OR then you can replace the line I mentioned (I've also now added this to the script). No worries about payment... I've benefited a lot from this site's community.
You are right actually, it works exactly as it should. Thank you so much man!
1

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 -->

1 Comment

Thank you for your solution! I only now realize how off I really was... I was thinking I was missing each function and proper and or statement, but this is something else entirely...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.