0

I am trying to hide specific table rows using checkboxes as filters to hide the rows. I have searched tons of different examples for checkboxes, css visibility, jquery, etc, etc. However, I have not found any examples that fit my scenario, and I can't seem to hack together a custom solution based on examples I have found.

- Checking a checkbox should REMOVE ANY ROWS that DO NOT match checkbox value. For example, if I check the "Male" checkbox, it should HIDE the rows which DO NOT have the "gender" value of "male" - Unchecking the checkbox should make corresponding rows visible again - Code should be able to handle multiple checkboxes. For example if I check the "Droid" checkbox AND I check the "Male" checkbox, NO RESULTS should display, because NO RESULTS exist that MATCH BOTH conditions.

UPDATE:

I screwed up the initial logic.

  • If NO checkboxes are checked, SHOW EVERYTHING.
  • If a checkbox is checked, show the corresponding rows for that checkbox. Iterate any checkboxes that are checked, and show corresponding rows. Hide any rows that are NOT checked.
  • If NO checkboxes are checked, SHOW EVERYTHING.

JSFiddle Link

table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px; }
tr:nth-child(even){background-color: #f2f2f2}
th { background-color: #0099ff; color: white; }
table, th, td { border: 1px solid black; }
* { box-sizing: border-box; }
body { margin: 0; }
.column {
    float: left;
    padding: 10px;
    height: 300px; /* Should be removed. Only for demonstration */
}
.left { width: 75%; }
.right { width: 25%; }
.row:after {
    content: "";
    display: table;
    clear: both;
}
<div class="column left">
<table>
	<thead>
		<th>Name</th>
		<th>Occupation</th>
		<th>Gender</th>
		<th>Race</th>
	</thead>
	<tbody>
		<tr gender="male" race="sith">
			<td>Darth Vader</td>
			<td>Dark Lord of the Sith</td>
			<td>Male</td>
			<td>Sith</td>
		</tr>
		<tr gender="male" race="human">
			<td>Boba Fett</td>
			<td>Bounty Hunter</td>
			<td>Male</td>
			<td>Human</td>
		</tr>
		<tr gender="male" race="unknown">
			<td>Yoda</td>
			<td>Jedi Master</td>
			<td>Male</td>
			<td>Unknown</td>
		</tr>
		<tr gender="non-binary" race="droid">
			<td>R2D2</td>
			<td>Astromech Droid</td>
			<td>Non-Binary</td>
			<td>Droid</td>
		</tr>		
	</tbody>
</table>
</div>
<div class="column right">
<div><b>Filters</b></div>
<div><b>Gender</b></div>
<div><input type="checkbox" value="male">Male</input></div>
<div><input type="checkbox" value="non-binary">Non-Binary</input></div>
<div><b>Race</b></div>
<div><input type="checkbox" value="sith">Sith</input></div>
<div><input type="checkbox" value="human">Human</input></div>
<div><input type="checkbox" value="unknown">Unknown</input></div>
<div><input type="checkbox" value="droid">Droid</input></div>
</div>

1
  • So... Where's the JavaScript you tried so far? Commented Oct 27, 2017 at 15:47

2 Answers 2

2

The best way to do this kind of thing is to have a single "update" function that figures out which rows should be visible, which should not be visible, and applies those styles (this is close to how it would work in something like ReactJS too). Here's an example of how to do that.

I've altered your checkboxes so it's easy to tell in code which ones are for race and which are for gender:

<div class="column right">
   <div><b>Filters</b></div>
   <div><b>Gender</b></div>
   <div><input type="checkbox" class="gender" value="male">Male</input></div>
   <div><input type="checkbox" class="gender" value="non-binary">Non-Binary</input></div>
   <div><b>Race</b></div>
   <div><input type="checkbox" class="race" value="sith">Sith</input></div>
   <div><input type="checkbox" class="race" value="human">Human</input></div>
   <div><input type="checkbox" class="race" value="unknown">Unknown</input></div>
   <div><input type="checkbox" class="race" value="droid">Droid</input></div>
</div>

Now we attach a listener so that we update all the table rows whenever a checkbox changes:

$("input").on("click", updateRows );

function updateRows() {
    $("table tr").each( function() {
        var $row = $(this);
        updateRow( $row );
    });
}

function updateRow( $row ) {
    var gender = $row.attr("gender");
    var race = $row.attr("race");
    var visibility = isGenderVisible( gender ) && isRaceVisible( race );
    $row.css("visibility", visibility ? "visible": "hidden");
}

function isGenderVisible( gender ) {
    var gendersChecked = $("input.gender").map( function() {
        if ( this.checked ) return this.value;
    });
    if ( gendersChecked.length === 0 ) return true;
    if ( gendersChecked.length === 1 ) return gender === gendersChecked[0];
    return false;
}

function isRaceVisible( race ) {
    var racesChecked = $("input.race").map( function() {
        if ( this.checked ) return this.value;
    });
    if ( racesChecked.length === 0 ) return true;
    if ( racesChecked.length === 1 ) return race === racesChecked [0];
    return false;
}
Sign up to request clarification or add additional context in comments.

5 Comments

The code looks great! I love that you made it more dynamic in anticipation of adding more attributes, which I plan to do. However, I am unable to get it working in JSFifddle... =/ jsfiddle.net/h1dpxkqy
Sorry - my jQuery is a bit rusty. Try updated code here jsfiddle.net/1f13Lxvp
Glad you like the code style - I'm a big fan of breaking things down into small specialised functions where it's easy to see exactly what each part is doing, and giving each one a meaningful name. Makes it much easier to maintain later!
Duncan thank you that looks much better! Would you be so kind as to expand on this question. I screwed up when I initially defined my question. Perhaps I should start another thread or update this one, but maybe my additional requirement is an easy tweak. Basically the behavior I really wanted was for it to filter based on everything that is checked. So in this example if both "Male" and "Non-Binary" were checked it would show ALL genders with those values. If "Male" and "Non-Binary" and "Droid" were checked, it would show R2D2. I would be adding additional filters to this as well.
What I should of said initially is... If NO filters are checked, show everything, if a filter is checked, show anything corresponding to that filter.
1

Duncan Thacker's answer describes the general approach quite accurately, but as I had already finished my working example, here you go... I also think that my approach is a bit easier to grasp and less bloated with different functions for each filter, but it might be a bit too simplistic and need to be extended, depending on what future filter mechanisms you might have that exceed this simple code example.

var tableRows = $('.column.left tbody tr'),
    filterBoxes = $('.column.right :checkbox').on('change', filterTable);

function filterTable() {
  var filter_selector = '';
  $('.column.right :checked').each(function() {
    filter_selector += '[' + $(this).attr('name') + '=' + '"' + $(this).val() + '"]';
  });
  if (filter_selector.length < 1) {
    tableRows.show();
  } else {
    tableRows.hide().filter(filter_selector).show();
  }
}
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px; }
tr:nth-child(even){background-color: #f2f2f2}
th { background-color: #0099ff; color: white; }
table, th, td { border: 1px solid black; }
* { box-sizing: border-box; }
body { margin: 0; }
.column {
    float: left;
    padding: 10px;
    height: 300px; /* Should be removed. Only for demonstration */
}
.left { width: 75%; }
.right { width: 25%; }
.row:after {
    content: "";
    display: table;
    clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="column left">
<table>
	<thead>
		<th>Name</th>
		<th>Occupation</th>
		<th>Gender</th>
		<th>Race</th>
	</thead>
	<tbody>
		<tr gender="male" race="sith">
			<td>Darth Vader</td>
			<td>Dark Lord of the Sith</td>
			<td>Male</td>
			<td>Sith</td>
		</tr>
		<tr gender="male" race="human">
			<td>Boba Fett</td>
			<td>Bounty Hunter</td>
			<td>Male</td>
			<td>Human</td>
		</tr>
		<tr gender="male" race="unknown">
			<td>Yoda</td>
			<td>Jedi Master</td>
			<td>Male</td>
			<td>Unknown</td>
		</tr>
		<tr gender="non-binary" race="droid">
			<td>R2D2</td>
			<td>Astromech Droid</td>
			<td>Non-Binary</td>
			<td>Droid</td>
		</tr>		
	</tbody>
</table>
</div>
<div class="column right">
<div><b>Filters</b></div>
<div><b>Gender</b></div>
<div><input type="checkbox" name="gender" value="male">Male</input></div>
<div><input type="checkbox" name="gender" value="non-binary">Non-Binary</input></div>
<div><b>Race</b></div>
<div><input type="checkbox" name="race" value="sith">Sith</input></div>
<div><input type="checkbox" name="race" value="human">Human</input></div>
<div><input type="checkbox" name="race" value="unknown">Unknown</input></div>
<div><input type="checkbox" name="race" value="droid">Droid</input></div>
</div>

3 Comments

This is awesome as well, and works perfectly in JSFiddle, nice simple concise, easy to understand solution! jsfiddle.net/89dzvmam
Glad you like the solution! You know you didn't have to copy&paste all this into JSFiddle, right? :) You can just click the button "Run code snippet" to see the result! ;)
I put it into JSFiddle because it wasnt working correctly copying it straight to an html file, and when I view the solution in JSFiddle I can copy the code in its entirety. ;-)

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.