Фильтр страницы с несколькими флажками jQuery

Я пытался выяснить, как это сделать правильно, и, похоже, не могу заставить его работать.

Я хочу использовать jQuery, чтобы выбирать, что я хочу показать на странице. Я искал и пытался найти какой-нибудь сценарий, какой-то работал, но не совсем так, как я хотел.

На странице будут использоваться флажки в качестве «тегов», например искусство, компьютеры, здоровье, видеоигры.

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

Тогда на странице будут результаты, и к каждому результату будут прикреплены теги.

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

Я хочу иметь возможность нажимать на искусство и видеоигры, и он будет отображать все, что имеет как искусство, так и видеоигры, поэтому результат 4. Или я могу просто выбрать компьютеры и получить результаты 1 и 3.

Я думал, что могу сделать что-то вроде

 $('.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();
      });      
 });

но это не работает, он просто все скрывает, но потом не возвращается, чтобы показать остальное. Я знаю, что логика совершенно неправильная, я не думаю, что я должен использовать каждый таким образом? Может быть, использовать его, чтобы захватить все классы в массиве, а затем показать li, у которых есть эти классы?

Любые идеи?


person derno    schedule 29.06.2011    source источник


Ответы (5)


  • Используйте событие .change() флажка.
  • .hasClass() возвращает логическое.
  • Имеет смысл хранить эту информацию в атрибуте, отличном от class, например rel или data-*.

$('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();

Демо: http://jsfiddle.net/mattball/d2v4Q/


@Justin спрашивает

Как бы вы изменили это, чтобы возвращать только те списки, которые соответствуют всем отмеченным флажкам, вместо любого из них?

Заполните (какой бы атрибут вы ни использовали) из каждого проверенного ввода в массив, String.join('.') это создайте один большой селектор классов, а затем .filter() <li>s, как и раньше:

var selector = $('input:checked').map(function ()
{
    return $(this).attr('rel');
}).get().join('.');
$lis.filter(selector).doWhatever();
person Matt Ball    schedule 29.06.2011
comment
Как бы вы изменили это, чтобы возвращать только lis, которые соответствуют всем отмеченным флажкам, вместо любого из них? - person Justin ᚅᚔᚈᚄᚒᚔ; 29.06.2011
comment
Большое спасибо за быстрый ответ! Работает, и это просто, так что мне это нужно. Спасибо! Просто любопытно, есть ли простой способ начать с их всех отображаемых, тогда после того, как я щелкну по одному, он начнет фильтрацию. Я полагаю, изменяя $ ('. Results ›li) .hide () на show (), затем добавляю $ (' input: not (: checked) '). Каждый с hide () внутри? - person derno; 30.06.2011
comment
@derno, я действительно добавил дополнительный код, чтобы запустить все скрытые <li>. Просто удалите .find('input:checkbox').change() - см. jsfiddle.net/mattball/gd276 - person Matt Ball; 30.06.2011
comment
@derno также, если мой ответ решил вашу проблему, не могли бы вы принять его ? - person Matt Ball; 30.06.2011
comment
@ matt-ball Это действительно работает в самом начале, но если вы снимете все флажки после проверки некоторых, то он не отобразит все. Есть идеи, как это сделать? Также - принял ваш ответ, не знал об этом, так как я новенький. - person derno; 30.06.2011
comment
потрясающе, что отлично работает, большое вам спасибо! и спасибо за советы StackOverflow. - person derno; 30.06.2011

Я немного изменил решение Мэтта, чтобы оно выполняло то, что вы просили. По крайней мере, как я это интерпретировал (показаны только элементы, соответствующие всем выбранным категориям). Это ни в коем случае не так элегантно, как решение Мэтта:

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>

И 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();

Если вы хотите попробовать, вот моя запись jsfiddle (созданная Мэттом)

person André Laszlo    schedule 29.06.2011
comment
Спасибо за это другое решение, которое почти противоположно Мэтту, которое также может быть очень полезно для меня! - person derno; 30.06.2011
comment
не могу, у меня всего 10 повторений, нужно 15 = ( - person derno; 01.07.2011

Попробуйте воспользоваться grep функцией. Псевдопсевдокод:

$(yourstuff).grep(filter1).grep(filter2)...
person André Laszlo    schedule 29.06.2011
comment
Как именно это здесь полезно? - person Matt Ball; 29.06.2011
comment
будет отображать все, что имеет как искусство, так и видеоигры ... поэтому я думаю, что цепочка grep будет реализовывать эту логику, но я могу ошибаться. - person André Laszlo; 29.06.2011
comment
Тем не менее, мне нравится ваше решение. Отлично. - person André Laszlo; 29.06.2011

Две проблемы.

  1. Селектор входа -.is - это функция, а не селектор.
  2. hasClass - тоже не селектор.

Оба возвращают true или false, поэтому вы не можете работать с их результатами как с объектом jQuery.

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

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

           $('.'+$(this).attr('class')).show();
      });      
 });
person Jamie Treworgy    schedule 29.06.2011
comment
Re: проблема №1, OP не пытается использовать .is() в качестве селектора. - person Matt Ball; 29.06.2011
comment
.is(..).each(..)? да, он такой. - person Jamie Treworgy; 29.06.2011
comment
Извините, не пытаюсь быть педантичным - теперь я понимаю, что вы имеете в виду. актуальная проблема №1 заключается в том, что .is() возвращает логическое значение. - person Matt Ball; 29.06.2011
comment
В своем использовании он пытался использовать его как селектор: checked. Это то, что я имел в виду. - person Jamie Treworgy; 29.06.2011

$('.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');​

Мне очень нравится .on () :) [jQuery 1.7+]

http://jsfiddle.net/ne8dy/

person J Bryan Price    schedule 06.07.2012