# Interactive search filter for HTML table

I know there are many great plugins on the Net nowadays. But due to safety issues, external plugin are restricted. Thus, I wrote some JavaScript for an interactively searchable HTML table. The main features I need are a vertically scrollable table and interactive filtering. Since the window size is not fixed, I also added width adjustments.

The fiddle

1. Can someone please check if there are any parts I can refine OR that should be fixed? (i.e. I should define this as a var, etc.)

2. I have replaced $("table#table-body tr:gt(0)").each() to $(row + ":gt(0)").each(), is the code still correct (note: var bodyTr = $(row + ":visible:eq(0) td");)? JavaScript //Perparing table /* *comment */$("<div>", {class: "tablewrapper"}).insertBefore("table#table-body");
$("<table>", {class: "header"}).appendTo($("<div>", {class: "headerwrapper"}).appendTo("div.tablewrapper"));
$("table#table-body").appendTo($("<div>", {class: "bodywrapper"}).appendTo("div.tablewrapper"));
$("table#table-body>thead").clone().val("").appendTo("table.header");$("table.header>tr").removeClass("header_hidden");
$("table#table-body").find("thead tr").addClass("header_hidden");$("table#table-body").find("tbody td:nth-child(2)").addClass("lefty");
$("<input>", {type: "text"}).attr("id","search-criteria").appendTo($("<div>", {class:"s_box"}).insertAfter("div.headerwrapper"));
$("<div>").attr("id","count").insertAfter("div.s_box"); resizeTable(); var bodyTd =$("table#table-body tr td");

$(window).resize(resizeTable); //search function$("#search-criteria").on("keyup", function () {
var keyword = $(this).val().replace(/[Ａ-Ｚａ-ｚ０-９]/g, function (td_word) { return String.fromCharCode(td_word.charCodeAt(0) - 0xFEE0); }).toLowerCase(); var row = "table#table-body tbody>tr"; if (keyword !== "") {$(row).each(function () {
var td_word = $(this).text().toLowerCase(); //shorthand if function$(this).closest(row)[td_word.indexOf(keyword) !== -1 ? 'show' : 'hide']();
});
var srowCount = $(row).filter(":visible").length; document.getElementById('count').innerHTML = srowCount; if (srowCount === 0) { if(!$(row).last().hasClass('s_empty'))
{
("table#table-body tbody").last().append('<tr class="s_empty"><td colspan="5" style="text-align:center">Search not found</td></tr>'); }("tr.s_empty").show();
} else {
$("tr.s_empty").remove(); } } else {$("tr.s_empty").remove();
$(row).show(); document.getElementById('count').innerHTML =$(row).length;
}

});

var row = "table#table-body tbody>tr";
var srowCount = $(row).filter(":visible").length; document.getElementById('count').innerHTML = srowCount; function resizeTable() { //width adjustments$("table.header").width($("#table-body").width());$("div.s_box").width(($("div.headerwrapper").width()-10)).height(($("table.header").height()-9));
$("input#search-criteria").width(($("div.headerwrapper").width()-30)).height(($("div.s_box").height()-0.05)); var counter_h = ($("table.header").height()/2+$("table.header").height()-1);$("div#count").css({"top":counter_h});

var bodyTr = $("table#table-body tbody>tr:visible:eq(0) td"); console.log(bodyTr);$("table.header tr:first th").each(function (index, value) {
$(this).width(bodyTr.eq(index).width()); }); //apply widths to every TD$("table#table-body tr:gt(0)").each(function () {
$(this).children().each(function (index) {$(this).width(bodyTr.eq(index).width());
});
});
}


CSS

div.tablewrapper, div.headerwrapper, div.bodywrapper {
border:0px;
}

background-color:#1BA7F5;
}

div.bodywrapper {
height:100px;
overflow-y:scroll;
border-bottom:solid 2px #1BA7F5;
}

border:0px;
border-collapse:collapse;
border-spacing:0px;
text-align:center;
}

line-height:32px;
background-color:#1BA7F5;
color:#FFF;
}

text-align:left;
font-weight: normal;
}

table#table-body {
width:100%;
}

table#table-body tr {
line-height:30px;
border-top:1px solid #C4C4C4;
}

display:none;
}

table#table-body tr:hover {
background-color:#FFFF99;
}

div.s_box {
background: #c4c4c4;
box-sizing: border-box;
}

input#search-criteria {
-webkit-appearance: none;
border: none;
font-size: 13px;
line-height: 23px;
background: #fff;
}

input#search-criteria:focus{
outline:none;
}

div#count {
position: absolute;
right: 17px;
color: #FFF;
background-color: #9EB4C2;
line-height: 19px;
font-size: 15px;
}

table#table-body tbody td.lefty {
text-align:left;
}


Code like this should be encapsulated and written in a way, so that it can be applied to any table, possibly even multiple tables on the same page. Currently you are putting everything in the global namespace and limiting yourself to a specific table by hard coding the id table-body (and using more IDs in the code).

You should instead consider implementing it as a jQuery plugin.

$(this).closest(row)[td_word.indexOf(keyword) !== -1 ? 'show' : 'hide']();  Can be simplified to $(this).closest(row).toggle(td_word.indexOf(keyword) !== -1);

• Thank you RoToRa. I understand what you are saying, although I am not skilled and knowledge enough yet to do that yet. 1 month ago, I knew pretty much nothing about JavaScript. Hope you can understand and that is also why I am trying to ask people to review it. ... thanks for the if > toggle. this is the use of .toggle( display ) right? (just read it on JQuery API now.) PS. if it is not too much, can you explain how I can encapsulate it? Perhaps I can try it myself from your example/explanation. Unless you are super kind and decide to review it.
– Maki
Mar 3, 2015 at 15:15
• RoToRa, I have tried to create a few new lines (1-21) if i didn't misunderstand what you are saying about encapsulating. 1) Is that the right idea, 2) how would I place the original parts into function (a) now?
– Maki
Mar 4, 2015 at 2:03