Javascript Filter on table, ol, ul...
It’s very common to enter a keyword and then filter it in a table or list. The easiest way could be go through each item of the table or list and then compare the keyword with the inner html of that item. But there is a drawback of this method. For instance, how to do filter in a table which has rows whose rowspan are set to bigger than 1? The code will break the layout of that table completely.
The method will come out with is to add a matching keyword to every item that are filterable. In other words, instead of comparing with the inner html, the code do it with the matching keyword. This gives the filter more flexibility. We will discuss the code a little bit belows. Note that it’s built on Prototype and used in Ruby on Rails. So, we have helper function to generate javascript in view too. But here, we just talk about the pure javascript part.
Here is an EXAMPLE
function strip_spaces(stripee) {
return stripee.replace(/(^[ ]*) | ([ ]*$)/g,'');
}
function filter(id, criteria) {
var t = $(id);
if (!t) { return; }
t.getElementsByClassName('no_matched_notice').each(function(elem) {
elem.remove();
});
var notice_msg = 'No matching data found!';
criteria = strip_spaces(criteria);
empty_input = criteria.length === 0;
var matched_none = true;
t.childElements().each(function(elem) {
// if the user doesn't input anything, then show all the elements
if (!elem.matched_strs || empty_input) {
Element.show(elem);
} else {
// else find the element
matched = false;
elem.matched_strs.each(function(str) {
if (str.toUpperCase().indexOf(criteria.toUpperCase()) != -1) {
matched = true;
matched_none = false;
return;
}
});
matched ? Element.show(elem) : Element.hide(elem);
}
});
if (matched_none && !empty_input) {
var tag = t.tagName;
var ins = null;
switch (tag) {
case "TBODY":
case "TABLE":
ins = new Insertion.Bottom(t, "<tr class=\"no_matched_notice\"><td colspan='100'>" + notice_msg + "</td></tr>");
break;
case "OL":
case "UL":
ins = new Insertion.Bottom(t, "<li class=\"no_matched_notice\">" + notice_msg + "</li>");
break;
default:
ins = new Insertion.Bottom(t, "<" + tag + " class=\"no_matched_notice\">" + notice_msg + "</" + tag + ">");
break;
}
}
}
In html, all we need to do are:
1) add an array of keyword to each item which is filterable
$('tr_01').matched_strs = ["apple", "banana", "pineapple", ..., "pear"])
$('tr_02').matched_strs = ["bamboo", "eggplant", "cabbage", ..., "pepper"])
...
$('tr_02').matched_strs = ["elephant", "tiger", "monkey", ..., "fish"])
2) add a text field to enter keyword:
<input id="keyword" type="text" />
3) bind filter function to keyword’s event:
$('keyword').onkeyup = function() {filter('food', this.value);};
$('keyword').onchange = function() {filter('food', this.value);};
That’s it! :)
