18

I have multiple lists on one page (multiple categories of products) like this:

<h3>Category 1</h3>
<ul id="category1">
    <li>item1</li>
    <li>item2</li>
    <li>item3</li>
</ul>
<h3>Category 2</h3>
<ul id="category2">
    <li>item27</li>
    <li>item28</li>
</ul>

The amount of lists is variable.

I would like a filter like on the demo page here http://static.railstips.org/orderedlist/demos/quicksilverjs/jquery.html.

But it should search over the different lists.

If the user searches for "2" then the result should be:

<h3>Category 1</h3>
<ul id="category1">
    <li>item2</li>
</ul>
<h3>Category 2</h3>
<ul id="category2">
    <li>item27</li>
    <li>item28</li>
</ul>

If he searches for "1" then it should be (don't show h3 title for list where there are no results):

<h3>Category 1</h3>
<ul id="category1">
    <li>item1</li>
</ul>

Can someone help me?

Thanks in advance!

Dante
  • 525
  • 3
  • 8
  • 21

2 Answers2

56

How about something like this:

HTML

<input type="text" />

<ul id="category1">
    <li>item1</li>
    <li>item2</li>
    <li>item3</li>
</ul>
<ul>
    <li>item27</li>
    <li>item28</li>
</ul>

JS

$(function(){

    $('input[type="text"]').keyup(function(){

        var searchText = $(this).val();

        $('ul > li').each(function(){

            var currentLiText = $(this).text(),
                showCurrentLi = currentLiText.indexOf(searchText) !== -1;

            $(this).toggle(showCurrentLi);

        });     
    });

});

http://jsfiddle.net/EFTZR/146/

Another solution using filter(), which is mentioned below:

$('input[type="text"]').keyup(function(){

    var that = this, $allListElements = $('ul > li');

    var $matchingListElements = $allListElements.filter(function(i, li){
        var listItemText = $(li).text().toUpperCase(), 
            searchText = that.value.toUpperCase();
        return ~listItemText.indexOf(searchText);
    });

    $allListElements.hide();
    $matchingListElements.show();

});

http://jsfiddle.net/EFTZR/441/

Johan
  • 31,613
  • 48
  • 166
  • 272
  • 1
    Looks magnificent! I've updated my question with the h3 tags to be shown or not. Can you help me with that too? Thanks for your answer anyway! – Dante Feb 21 '12 at 09:45
  • 2
    Adding .toLowerCase() to the text value and the comparision makes it capital independent! – Dante Feb 21 '12 at 10:01
  • Thanks works great, It would be good if you could also add **No results found** text, i used [this](http://stackoverflow.com/a/15924812/2218697) to find the element length which has display:block style. If the length is 0 then insert a bootstrap alert div like `$('.message').html(
    )`
    – Shaiju T Jul 12 '16 at 10:10
  • What does the `~` character in `return ~listItemText.indexOf(searchText);` do? – connexo Sep 27 '17 at 06:20
  • 1
    @connexo https://stackoverflow.com/questions/12299665/what-does-a-tilde-do-when-it-precedes-an-expression – Johan Sep 27 '17 at 09:03
2

You can do this with the filter method in jQuery:

var valueToSearch = "item1"; // this one should come from the search box
var allListItems = $("ul > li");
var filteredItems = allListItems.filter(function(index) {
    var listItemValue = $(this).text();
    var hasText = listItemValue.indexOf(valueToSearch) > -1;
    return hasText;
});

Next, you can display the values in the filteredItems variable in a list or something like that, using a for loop.

Jesse van Assen
  • 2,124
  • 2
  • 15
  • 18