45

I found a Jquery script that does the table filtering stuff based on input field. This script basically takes the filter, splits each word and filters table rows with each word. So at the end you'll have a list of rows that have all the words in the input field.

http://www.marceble.com/2010/02/simple-jquery-table-row-filter/

var data = this.value.split(" ");

$.each(data, function(i, v){
     jo = jo.filter("*:contains('"+v+"')");
});

Now, what I need is that instead of filtering rows that contains each of the words in the input field. I want to filter all the rows that contain at least one of the word in the input field.

One way I've tried is to take each filtered lists into an array...

  var rows = new Array();

 $.each(data, function(i, v){
     rows[i] = jo.filter("*:contains('"+v+"')");
 });

At this stage, I have to make a UNION of all the rows in "rows" array and show them. I'm lost on how to do that exactly.

Above script in action - http://marceble.com/2010/jqueryfilter/index.html?TB_iframe=true&width=720&height=540

If I type "cat six" in the filter, I want to show three rows.

RKodakandla
  • 3,318
  • 13
  • 59
  • 79

9 Answers9

88

Have a look at this jsfiddle.

The idea is to filter rows with function which will loop through words.

jo.filter(function (i, v) {
    var $t = $(this);
    for (var d = 0; d < data.length; ++d) {
        if ($t.is(":contains('" + data[d] + "')")) {
            return true;
        }
    }
    return false;
})
//show the rows that match.
.show();

EDIT: Note that case insensitive filtering cannot be achieved using :contains() selector but luckily there's text() function so filter string should be uppercased and condition changed to if ($t.text().toUpperCase().indexOf(data[d]) > -1). Look at this jsfiddle.

nrodic
  • 3,026
  • 3
  • 33
  • 38
  • 3
    i love this solution. very comprehensive and takes advantage of jquery's filter() method. – taylor michels May 02 '14 at 14:08
  • This helped me a load. I love how simplistic it is even though its so powerful. @nrodic is the real MVP – DeanMWake Feb 27 '15 at 13:41
  • Works well, but it matches *any* rows that contain the latest term entered. Is there a way for it to search the results of the first term for the second term? – Timmah Mar 19 '15 at 04:22
  • @Timmah - Do you want to show only rows that match ALL words? This [jsfiddle](http://jsfiddle.net/ukW2C/1064/) might be what you need. – nrodic Mar 19 '15 at 13:48
  • @nrodic - That's right, I asked **[here](http://stackoverflow.com/questions/29137992/loop-sequentially-through-an-array-with-another-array-with-javascript/29139436)** and got a very similar answer, but thanks anyway – Timmah Mar 19 '15 at 22:12
  • 2
    This is a great solution. Can you make it so it's not case sensitive? – Kennyomar Nov 02 '15 at 16:40
  • I was able to find the workaround yesterday, which was somewhat like yours. Thank you @nrodic – Kennyomar Nov 03 '15 at 16:33
30

There's no need to build an array. You can address the DOM directly.

Try :

rows.hide();
$.each(data, function(i, v){
    rows.filter(":contains('" + v + "')").show();
});

DEMO

EDIT

To discover the qualifying rows without displaying them immediately, then pass them to a function :

$("#searchInput").keyup(function() {
    var rows = $("#fbody").find("tr").hide();
    var data = this.value.split(" ");
    var _rows = $();//an empty jQuery collection
    $.each(data, function(i, v) {
        _rows.add(rows.filter(":contains('" + v + "')");
    });
    myFunction(_rows);
});

UPDATED DEMO

Rick Smith
  • 9,031
  • 15
  • 81
  • 85
Beetroot-Beetroot
  • 18,022
  • 3
  • 37
  • 44
  • 1
    think I spoke too soon. Your answer addresses my question exactly but I need a bit more. I don't want to show the rows immediately as I find a matching value. I need to make a list of all those rows and pass them to another function. – RKodakandla Jun 12 '13 at 22:53
  • After you've filtered and removed the filter, no result in given, whilst all of them should be displayed – Dane411 Nov 17 '13 at 16:02
  • 3
    Dane you're right - my demo doesn't address that aspect. Try [this update](http://jsfiddle.net/tXNQd/122/), in which an empty filter is handled as a special case. – Beetroot-Beetroot Nov 17 '13 at 19:28
  • Simple and clean. Any way to make it case INsensitive? – nclsvh Jun 09 '16 at 12:39
  • @RickSmith You have any idea to make this case insensitive? Cant figure it out – nclsvh Jun 13 '16 at 08:09
  • See this answer for a override for the filter, to make it case insensitive: https://stackoverflow.com/a/8747204/2214980 – MichaelCleverly Nov 28 '19 at 09:37
5

I chose @nrodic's answer (thanks, by the way), but it has several drawbacks:

1) If you have rows containing "cat", "dog", "mouse", "cat dog", "cat dog mouse" (each on separate row), then when you search explicitly for "cat dog mouse", you'll be displayed "cat", "dog", "mouse", "cat dog", "cat dog mouse" rows.

2) .toLowerCase() was not implemented, that is, when you enter lower case string, rows with matching upper case text will not be showed.

So I came up with a fork of @nrodic's code, where

var data = this.value; //plain text, not an array

and

jo.filter(function (i, v) {
    var $t = $(this);
    var stringsFromRowNodes = $t.children("td:nth-child(n)")
    .text().toLowerCase();
    var searchText = data.toLowerCase();
    if (stringsFromRowNodes.contains(searchText)) {
        return true;
        }
    return false;
})
//show the rows that match.
.show();

Here goes the full code: http://jsfiddle.net/jumasheff/081qyf3s/

  • Added benefit, back-spacing in your version restores all values to the display. – noogrub Jan 27 '15 at 17:00
  • 1
    Just a note for future readers: You can easily change the `$t.children()` selector from `"td:nth-child(n)"` to a class like `"filter-criteria"`. Then adding that class to each `` limits which columns the filter searches. – vastlysuperiorman Aug 14 '15 at 21:48
  • `stringsFromRowNodes.contains` needs to be changed to `stringsFromRowNodes.includes`. I made an edit to the code in the post to reflect this. (May be pending review) I did not change the JSFiddle – Karl_S Aug 17 '17 at 13:25
4

i have a very simple function:

function busca(busca){
    $("#listagem tr:not(contains('"+busca+"'))").css("display", "none");
    $("#listagem tr:contains('"+busca+"')").css("display", "");
}
4

based on @CanalDoMestre's answer. I added support for the blank filter case, fixed a typo and prevented hiding the rows so I can still see the column headers.

    $("#filterby").on('keyup', function() {
        if (this.value.length < 1) {
            $("#list tr").css("display", "");
        } else {
            $("#list tbody tr:not(:contains('"+this.value+"'))").css("display", "none");
            $("#list tbody tr:contains('"+this.value+"')").css("display", "");
        }
    });
xeo
  • 807
  • 2
  • 7
  • 25
2

tr:not(:contains(.... work for me

function busca(busca){
    $("#listagem tr:not(:contains('"+busca+"'))").css("display", "none");
    $("#listagem tr:contains('"+busca+"')").css("display", "");
}
I_Am_Hated
  • 55
  • 3
2

nrodic has an amazing answer, and I just wanted to give a small update to let you know that with a small extra function you can extend the contains methid to be case insenstive:

$.expr[":"].contains = $.expr.createPseudo(function(arg) {
    return function( elem ) {
        return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
    };
});
David O'Regan
  • 2,684
  • 2
  • 13
  • 12
2

Adding one more approach :

value = $(this).val().toLowerCase();
$("#product-search-result tr").filter(function () {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
Kamran Ul Haq
  • 23
  • 1
  • 4
1

I used Beetroot-Betroot's solution, but instead of using contains, I used containsNC, which makes it case insensitive.

$.extend($.expr[":"], {
"containsNC": function(elem, i, match, array) {
return (elem.textContent || elem.innerText ||
"").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
}
});
Philipp S.
  • 58
  • 4