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.

9 Answers 9

89

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.

Sign up to request clarification or add additional context in comments.

7 Comments

i love this solution. very comprehensive and takes advantage of jquery's filter() method.
This helped me a load. I love how simplistic it is even though its so powerful. @nrodic is the real MVP
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 - Do you want to show only rows that match ALL words? This jsfiddle might be what you need.
This is a great solution. Can you make it so it's not case sensitive?
|
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

6 Comments

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.
After you've filtered and removed the filter, no result in given, whilst all of them should be displayed
Dane you're right - my demo doesn't address that aspect. Try this update, in which an empty filter is handled as a special case.
Simple and clean. Any way to make it case INsensitive?
@RickSmith You have any idea to make this case insensitive? Cant figure it out
|
5

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", "");
        }
    });

Comments

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/

3 Comments

Added benefit, back-spacing in your version restores all values to the display.
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 <td> limits which columns the filter searches.
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
4

i have a very simple function:

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

1 Comment

Should be tr:not(:contains.
2

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

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

Comments

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;
    };
});

Comments

2

Adding one more approach :

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

Comments

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;
}
});

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.