3

I've been trying to figure out how to do this properly and cannot seem to get it to work.

I want to use jQuery to essentially pick and choose what I want to show on a page. I've looked and tried to find some script, some kind of worked but not really how I wanted it to.

The page will use checkboxes as "tags", let's say arts, computers, health, video games

 <div class="tags">
 <label><input type="checkbox" class="arts" /> Arts </label>
 <label><input type="checkbox" class="computers" /> Computers </label>
 <label><input type="checkbox" class="health" /> Health </label>
 <label><input type="checkbox" class="video-games" /> Video Games </label>
 </div>

Then on the page there will be results and each result has tags attached to it.

 <ul class="results">
 <li class="arts computers">
     Result 1
 </li>
 <li class="video-games">
     Result 2
 </li>
 <li class="computers health video-games">
     Result 3
 </li>
 <li class="arts video-games">
     Result 4
 </li>
 </ul>

I want to be able to click on arts and video games and it will display everything that has both arts AND video-games, so result 4. Or be able to just choose computers and get back results 1 and 3.

I was thinking I could do something along the lines of

 $('.tags input').click( function() {
      $('.results > li').hide();
      //For each one checked
      $('input').is(':checked').each( function() {
           //Display that result
           $('.results li').hasClass($(this).attr('class')).show();
      });      
 });

but it doesn't work, it just hides everything but then doesn't come back to show the rest. I know the logic is completely wrong, I don't think i'm supposed to use the each in that way? Maybe use it to grab all of the classes in an array then show the li's that have those classes?

Any Ideas?

5 Answers 5

7
  • Use the .change() event of the checkbox.
  • .hasClass() returns a boolean.
  • It makes more sense to store that information an attribute other than class, such as rel or a data-* attribute.

$('div.tags').delegate('input:checkbox', 'change', function()
{
     var $lis = $('.results > li').hide();
     $('input:checked').each(function()
     {
          $lis.filter('.' + $(this).attr('rel')).show();
     });      
}).find('input:checkbox').change();

Demo: http://jsfiddle.net/mattball/d2v4Q/


@Justin asks

How would you change this to return only the lis that match all of the checked boxes instead of any one of them?

Stuff (whatever attribute you're using) from each checked input into an array, String.join('.') it to create one big class selector, and then .filter() the <li>s as before:

var selector = $('input:checked').map(function ()
{
    return $(this).attr('rel');
}).get().join('.');
$lis.filter(selector).doWhatever();
Sign up to request clarification or add additional context in comments.

6 Comments

How would you change this to return only the lis that match all of the checked boxes instead of any one of them?
Thanks so much for the quick response! Works and it's simple so I gotta love it. Thanks! Just curious if there was an easy way to start with them all displayed then after I click one it'll start to filter. I figure changing the $('.results > li).hide() to be show() then add a $('input:not(:checked)').each with a hide() inside?
@derno oh, I actually put in extra code to start all the <li>s hidden. Just remove the .find('input:checkbox').change() - see jsfiddle.net/mattball/gd276
@matt-ball That actually just works at the start but if you uncheck all of them after checking some, then it doesn't display everything. Any idea's on how to do that? Also - accepted your answer, didn't know about that since i'm new.
@derno No worries about being new :) Likewise you don't have to @user someone if you're commenting on one of their posts. So you want to show all the <li>s if no boxes are checked? jsfiddle.net/mattball/gZUrA
|
2

I've changed Matt's solution a bit so that it does what you asked. At least how I interpreted it (showing only items that matches all selected categories). It's by no means as elegant as Matt's solution though:

The HTML:

<div class="tags">
    <label><input type="checkbox" data-category="arts" /> Arts </label>
    <label><input type="checkbox" data-category="computers" /> Computers </label>
    <label><input type="checkbox" data-category="health" /> Health </label>
    <label><input type="checkbox" data-category="video-games" /> Video Games </label>
</div>

<ul class="results">
    <li data-category="arts computers">
        Result 1
    </li>
    <li data-category="video-games">
        Result 2
    </li>
    <li data-category="computers health video-games">
        Result 3
    </li>
    <li data-category="arts video-games">
        Result 4
    </li>
</ul>

And the JS:

$('div.tags').delegate('input:checkbox', 'change', function() {
    $('.results > li').hide();

    var selector = $('input:checked').map(function() {
        return $(this).attr('data-category');
    }).get();

    function matchesCategories(elem) {
        var elemCats = elem.attr('data-category');

        if (elemCats) {
            elemCats = elemCats.split(' ');
        } else {
            elemCats = Array();
        }
        for (var i = 0; i < selector.length; i++) {
            console.log("testing " + selector[i] + " in:");
            console.log(elemCats);
            if (jQuery.inArray(selector[i], elemCats) == -1) {
                return false;
            }
        }
        return true;
    }
    $('.results > li').each(function(i, elem) {
        if (matchesCategories(jQuery(elem))) {
            $(elem).show();
        }
    });

}).find('input:checkbox').change();

If you want to try it out, here's my jsfiddle entry (forked from Matt's)

2 Comments

Thanks for this other solution which does almost the opposite of Matt's, which also might be really useful for me!
cant, i only have 10 rep, need 15 =(
0

Try the grep function. Pseudopseudocode:

$(yourstuff).grep(filter1).grep(filter2)...

3 Comments

How, exactly, is that useful here?
"will display everything that has both arts AND video-games"... so I guess a chained grep will implement that logic, but I might be wrong.
Love your solution though. Nice.
0

Two problems.

  1. Input selector -.is is a function, not a selector.
  2. hasClass- also not a selector.

Those both return true or false so you can't operate on their results like a jQuery object.

http://jsfiddle.net/5z7M5/3/

 $('.tags input').click( function() {
      $('.results > li').hide();
      //For each one checked
      $('input:checked').each( function() {

           $('.'+$(this).attr('class')).show();
      });      
 });

4 Comments

Re: problem #1, the OP isn't trying to use .is() as a selector.
.is(..).each(..)? yeah he is.
Sorry, not trying to be pedantic - I see what you mean now. The actual problem #1 is that .is() returns a boolean.
In his usage, he was trying to use it like the ":checked" selector. That's what I meant.
0
$('.tags')
    .on('update', function() {
        // Limit the selector(s) to search for:
        var $filters = $(this).find('input:checked');

        // Get the class names of interest
        // Return null (rather than "") to keep them out of the result array
        var $classes = $filters.map(function(){ return this.className || null; });

        // Use .replace() if your checkboxes might target multiple classes
        var selector = $classes.get().join('.').replace(/ /g,'.');

        var $results = $('ul.results > li').hide();

        if (selector) 
            $results.filter('.'+selector).show();
    })

    // Relay any changes to the display-state container (.tags)
    .on('change','input[type="checkbox"]',function() {
        $(event.currentTarget).trigger('update');
    })

    // When first loaded, apply the server-supplied checkbox state(s) to the page:
    .trigger('update');​

I like .on() a lot :) [jQuery 1.7+]

http://jsfiddle.net/ne8dy/

Comments

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.