3

I have a series of a series of rows and checkboxes to filter them:

<ul> 
<li><input id="type-A" type="checkbox" checked="checked"> <a href="/A">A</a></li>
<li><input id="type-B" type="checkbox" checked="checked"> <a href="/B">B</a></li>
<li><input id="type-C" type="checkbox" checked="checked"> <a href="/C">C</a></li>
<li><input id="type-D" type="checkbox" checked="checked"> <a href="/D">D</a></li>
<li><input id="type-E" type="checkbox" checked="checked"> <a href="/E">E</a></li>
<li><input id="type-F" type="checkbox" checked="checked"> <a href="/F">F</a></li>
</ul>

<table>
<tr class="A">filler</tr>
<tr class="B">filler</tr>
<tr class="A B">filler</tr>
<tr class="C D">filler</tr>
<tr class="A F">filler</tr>
<tr class="A E F">filler</tr>
<tr class="F">filler</tr>
<tr class="C D E">filler</tr>
<tr class="A B C D E F">filler</tr>
</table>

I'd like to hide/show rows based on what is checked. Currently I'm using (with the help from this previous question: Use "this" to simplify code (simple jQuery) ):

$(function(){
  $("input[id^='type-']").change(function() {
    $("."+this.id.replace('type-','')).toggle(this.checked);
  }).change(); 
});

Which toggles what is shown every time a box is clicked and works great if each row only has one class. But they don't. How it's set up now, the order of clicking changes the rows that are shown. So I need to create a function that checks which checkboxes are checked and shows the rows that contain any of them. I'm not opposed to adding a button to make this happen.

I'd appreciate any help (and the direction to resources that could help me learn) you guys could give me!

Community
  • 1
  • 1
christina
  • 651
  • 3
  • 11
  • 17
  • `@christina` Why are you triggering a `change` event immediately after defining a handler? Is this what you want to do? – Alex Nov 22 '10 at 21:01
  • @Alex it's a quick way to set the visibility of the rows based on the initial state of the checkboxes. – kevingessner Nov 22 '10 at 21:03

3 Answers3

2

Modify the function to get a selector for all the checked check boxes.

$(function(){
  var $checkboxes = $("input[id^='type-']");
  $checkboxes.change(function() {
    var selector = '';
    $checkboxes.filter(':checked').each(function(){ // checked 
        selector += '.' + this.id.replace('type-','') + ', '; 
        // builds a selector like '.A, .B, .C, ' 
    });
    selector = selector.substring(0, selector.length - 2); // remove trailing ', '
    // tr selector
    $('table tr').hide() // hide all rows
       .filter(selector).show(); // reduce set to matched and show
  }).change(); 
});

EDIT: see jsfiddle

Josiah Ruddell
  • 29,697
  • 8
  • 65
  • 67
  • I think this is getting close to what I'm trying to do, but it still hides the row when one is selected and one not... for example, with A checked and B unchecked, a row with class A B is hidden, although it should be visible. – christina Nov 22 '10 at 20:30
  • @christina - try it with my edit. you may need a more specific row selector than table tr – Josiah Ruddell Nov 22 '10 at 20:34
  • i just made sure it works in jsfiddle. http://jsfiddle.net/B9Hnu/ I used a ul li for the table rows. From your link I think you need a better selector than $('table tr'). – Josiah Ruddell Nov 22 '10 at 21:00
  • I made a small typo that was screwing me up and it's working perfectly now. You are excellent. Thank you! – christina Nov 22 '10 at 21:02
0

jQuery has created this function for you! It's called .filter(), and it takes either a selector string, a function, a raw DOM element, or a jQuery object. In your case, I'd pass it a selector string. We can make use of jQuery's :has() selector, which takes a selector and returns the matched elements. So, if you wanted to select all rows (li elements) that contain checked checkboxes, you could do it like this:

$("li").filter(":has(input:checked)");

Or, we could eliminate our call to filter() and simply pass the entire selector to $():

$("li:has(input:checked)");

That will return all li elements that contain any checked checkboxes anywhere among it's descendants, not just it's direct children.

And putting it in the context of your .change() handler:

I'm assuming you want to show tr elements that have the same type as the li elements that contain checked checkboxes, and hide any tr elements that don't. So, we'll make use of the .toggle() function, which toggles the visibility of elements:

$(function(){
  $("input[id^='type-']").change(function() {
    $("."+this.id.replace('type-','')).toggle(this.checked);
    // show any tr elements that have the class relating to the type of the inputs that contain checked checkboxes... 
    $("li:has(input:checked)").each(function() {
      $("tr" + "." + this.id.replace(/type-/, "")).toggle();
    });
  }).change(); 
});
Alex
  • 64,178
  • 48
  • 151
  • 180
  • not quite what I'm looking for. I don't want to hide/show the li's containing the inputs, I want to show/hide the table rows with the related classes... – christina Nov 22 '10 at 20:26
0
  $("table tr").hide();
  $("input[id^='type-']").each(function() {
    element = $(this);
    $("table tr").each(function() {
      if($(this).hasClass(element.id.replace('type-','')) {
        if(element.is(":checked") {
          element.show();
        }
      }
    });
  }).change(); 
Mark Baijens
  • 13,028
  • 11
  • 47
  • 73