Footables column sorting is duplicating rows in table, Why? - javascript

I am adding footables to a table but the table has to have a tbody for each row. This is because I am adding footable sorting and filtering to an existing system that generates the html this way.
It seems to be causing the column sorting at the to be duplicating the table rows each time you try to sort the table by column heading and I cant see why.
The table structure is kinda like this:
<table data-filter="#filter" class="footable table demo">
<thead>
<tr>
<th>Name</th>
<th>Job Title</th>
<th>Status</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name1</td>
<td>Job Title1</td>
<td>Active</td>
<td>Description1</td>
</tr>
</tbody>
<tbody>
<tr>
<td>Name2</td>
<td>Job Title2</td>
<td>Disabled</td>
<td>Description2</td>
</tr>
</tbody>
</table>
javascript:
$(function () {
$("table").footable().bind("footable_filtering", function (e) {
var selected = $(".filter-status").find(":selected").text();
if (selected && selected.length > 0) {
e.filter += (e.filter && e.filter.length > 0) ? " " + selected : selected;
e.clear = !e.filter;
}
});
$(".clear-filter").click(function (e) {
e.preventDefault();
$(".filter-status").val("");
$("table.demo").trigger("footable_clear_filter");
});
$(".filter-status").change(function (e) {
e.preventDefault();
$("table.demo").trigger("footable_filter", {
filter: $("#filter").val()
});
});
});
I have also set up a working jsfiddle that demonstrates the issue:https://jsfiddle.net/35ht6kup/9/
Anybody have any idea how to resolve this?

You could rebuild the table with jQuery, example (to be refined with a better selector than 'table'):
$(document).ready(function(){
var thead = $('table thead');
var tbodyhtml;
$('table tbody').each(function(){
tbodyhtml += $(this).html();
});
$('table').html(thead);
$('table').append('<tbody>'+tbodyhtml+'</tbody>');
});

Related

Why my table filter is removing the table headers?

I'm trying to implement this table filter which i found at this tutorial but for some reason my filter is removing my table headers and in the examples it doesn't remove the headers, I wonder what I'm doing wrong here?
This is my table:
<input type="text" id="inputFilter" placeholder="Procurar agendamentos..">
<table class="table table-hover table-dark" id="tableAgendamentos">
<thead>
<tr>
<th scope="col">Data</th>
<th scope="col">Animal</th>
<th scope="col">Procedimento</th>
<th scope="col">Status</th>
<th scope="col">Valor</th>
<th scope="col">Nota Fiscal</th>
</tr>
</thead>
<tbody>
#foreach (Agendamento agendamento in Model.ListaAgendamentos)
{
<tr>
<th scope="row">#agendamento.DataHoraInicio</th>
<td>#agendamento.nomeAnimal</td>
<td>#agendamento.NomeServico</td>
#if(agendamento.prioridadeAgendamento == 3)
{
<td class="text-success">Em até 7 dias</td>
}else if(agendamento.prioridadeAgendamento == 2)
{
<td class="text-primary">Em até 30 dias</td>
}else
{
<td class="text-danger">Atrasado/Vencido</td>
}
<td>R$100,00</td>
<td>Baixar</td>
</tr>
}
</tbody>
</table>
This is my script:
<script>
$(document).ready(function(){
$("#inputFilter").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#tableAgendamentos tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});
</script>
This is how my table looks without searching anything
This is how my table looks after searching for some data
Thanks in advance.
Looks like the header is getting filtered out.
I think you could give it a try with an id for tbody instead of the whole table id in the script.
Looking at the tutorial, there seems to be a point at the end stating
Note that we start the search in tbody, to prevent filtering the table headers.
I think error is about this
$("#tableAgendamentos tr")
I think give a class name to tr instead of above code then try again

JQuery: search and filter a table by a single column

I want to search a table by the values in a single column.
The table looks like this:
<table class="table main-content">
<thead>
<td><b>Title</b></td>
<td><b>Name</b></td>
<td><b>State (D)</b></td>
<td><b>Party</b></td>
<td><b>Room</b></td>
<td><b>Phone #</b></td>
<td><b>Special Role(s)</b></td>
</thead>
<tbody id="congress">
<tr>
<td>Senator</td>
<td>Alexander, Lamar</td>
<td>TN</td>
<td class="republican">Rep.</td>
<td>455 Dirksen</td>
<td>(202) 224-4944</td>
<td></td>
</tr>
<tr>
<td>Senator</td>
<td>Barrasso, John</td>
<td>WY</td>
<td class="republican">Rep.</td>
<td>307 Dirksen</td>
<td>(202) 224-6441</td>
<td></td>
</tr>
...
I want to be able to search the table by a given column, say names (index 1) or state (index 2). I've tried jets.js but it only allows one instance per page while I require at least two. JQuery is preferred, JS is fine, and external libs are ok but not optimal.
Cheers!
Edit:
I've tried using the following:
var $rows = $('#congress tr');
$('#stateSearch').keyup(function() {
var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
$rows.show().filter(function() {
var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
return !~text.indexOf(val);
}).hide();
});
The above code searches all of the columns in the table. How can I adjust it to search only for a specific column? (By index.)
The goal is to hide all of the tr that don't match the query in the given column
Something like this
function isFound(name, state)
{
$("table tbody").find("tr").each (function(){
var trElem = $(this);
if (($(this).find("td:eq(1) a").text() == name) && ($(this).find("td:eq(2)").text() == state))
return trElem;
})
return false;
}
Usage:
if (tr = isFound ('Firstname Lastname', 'State'))
tr.remove();
or, if you have more than one elements, use a loop for removing
while (tr = isFound ('Firstname Lastname', 'State'))
tr.remove();
Here's an example that will hide all rows where the State column (index 3) is TN. You can adapt it as you need:
$('td:nth-child(3)').each (function(){
if( $(this).val() == 'TN' )
$(this).parent().hide();
});
Another easy solution would be to use Datatables, which have a built-in search feature and methods to search by column. It may be overkill for your project, but take a look anyway for the future.
DataTables Example
You could reinvent the wheel, but it's probably better to just use DataTables unless you have an expressed need to do otherwise:
var $table = $('table');
// Setup - add a text input to each footer cell
$table.find('tfoot th').filter(':eq(1),:eq(2)').css('visibility', 'visible').each(function() {
var title = $(this).text();
$(this).html('<input type="text" placeholder="Search ' + title + '" />');
});
// DataTable
var table = $table.DataTable({
lengthChange: false
});
// Apply the search
table.columns().every(function() {
var col = this;
$('input', this.footer()).on('keyup change', function() {
if (col.search() !== this.value)
col.search(this.value).draw();
});
});
table tfoot tr th {
visibility: hidden;
}
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs-3.3.7/jq-2.2.4/dt-1.10.13/r-2.1.1/datatables.min.css" />
<script type="text/javascript" src="https://cdn.datatables.net/v/bs-3.3.7/jq-2.2.4/dt-1.10.13/r-2.1.1/datatables.min.js"></script>
<table class="table table-striped main-content">
<thead>
<tr>
<th>Title</th>
<th>Name</th>
<th>State (D)</th>
<th>Party</th>
<th>Room</th>
<th>Phone #</th>
<th>Special Role(s)</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Title</th>
<th>Name</th>
<th>State (D)</th>
<th>Party</th>
<th>Room</th>
<th>Phone #</th>
<th>Special Role(s)</th>
</tr>
</tfoot>
<tbody id="congress">
<tr>
<td>Senator</td>
<td>Alexander, Lamar</td>
<td>TN</td>
<td class="republican">Rep.</td>
<td>455 Dirksen</td>
<td>(202) 224-4944</td>
<td></td>
</tr>
<tr>
<td>Senator</td>
<td>Barrasso, John</td>
<td>WY</td>
<td class="republican">Rep.</td>
<td>307 Dirksen</td>
<td>(202) 224-6441</td>
<td></td>
</tr>
</tbody>
</table>
try this:
var text = $(this).find('td:eq(1),td:eq(2)').text().replace(/\s+/g, ' ').toLowerCase();

filter the html table data using jquery

<table class="table table-hover">
<thead>
<tr><th> Block</th>
<th>Size</th></tr>
</thead>
<tbody id="poolTable" class="tbody">
<tr>
<td>78</td>
<td>18</td>
</tr>
<tr>
<td>52</td>
<td>21</td>
</tr>
<tr>
<td>54</td>
<td>19</td>
</tr>
</tbody>
</table>
Hi, I want to filter the html table data by using jquery,
can anyone try to resolve this please!!
Please try bellow JavaScript for to get content of each td
$("#filter").keyup(function(){
var filter = $(this).val();
$("#poolTable > tr").each(function(e){
cells = this.cells;
for(i=0; i< cells.length; i++){
alert(cells[i].innerHTML);
}
});
})
function filter(){
var text = $('#search').val();
$('#poolTable tr').show();
if (text != "") {
$('#poolTable tr td.number').each(function() {
if ($(this).text().indexOf(text) >= 0) {
$(this).parent().show();
return true;
} else {
$(this).parent().hide();
}
});
This works. Here number is the class name of td. It only filters the single column.
You can try this
https://sunnywalker.github.io/jQuery.FilterTable/
It is a jQuery plugin that will allow you to filter your table.

Modifying javascript table to search for specific data

The search form I'm using is found here: http://bootsnipp.com/snippets/featured/js-table-filter-simple-insensitive
I found a nice js search form created by Cyruxx that I am implementing on my site. Is it possible to modify this code to only search specific table headers?
For example I have:
<table class="table table-list-search">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>address</th>
</tr>
</thead>
<tbody>
<tr>
<td>107</td>
<td>John Doe</td>
<td>1074 example street</td>
</tr>
<tr>
<td>100</td>
<td>Henry</td>
<td>1111 example ave</td>
</tr>
</tbody>
</table>
How can I modify the code to only search the id column for example. In other words, typing the number '1' would only show table rows with a '1' in the 'id' header. Typing '1074' in my example would return 0 results while typing '1' would show both listings.
$(document).ready(function() {
var activeSystemClass = $('.list-group-item.active');
//something is entered in search form
$('#system-search').keyup( function() {
var that = this;
// affect all table rows on in systems table
var tableBody = $('.table-list-search tbody');
var tableRowsClass = $('.table-list-search tbody tr');
$('.search-sf').remove();
tableRowsClass.each( function(i, val) {
//Lower text for case insensitive
var rowText = $(val).text().toLowerCase();
var inputText = $(that).val().toLowerCase();
if(inputText != '')
{
$('.search-query-sf').remove();
tableBody.prepend('<tr class="search-query-sf"><td colspan="6"><strong>Searching for: "'
+ $(that).val()
+ '"</strong></td></tr>');
}
else
{
$('.search-query-sf').remove();
}
if( rowText.indexOf( inputText ) == -1 )
{
//hide rows
tableRowsClass.eq(i).hide();
}
else
{
$('.search-sf').remove();
tableRowsClass.eq(i).show();
}
});
//all tr elements are hidden
if(tableRowsClass.children(':visible').length == 0)
{
tableBody.append('<tr class="search-sf"><td class="text-muted" colspan="6">No entries found.</td></tr>');
}
});
});
First of all - that's not great search code, its not terribly preformant and mixes view and model concerns in a way that might get difficult to maintain. I would recommend using a pre-build widget, rather than copy-pasting code that you don't understand from blogs (or wherever).
To answer your question though, you can simply constrain which columns are searchable with a css class, and use that class as a search filter:
so change
var rowText = $(val).text().toLowerCase();
to
var rowText = $(val).find('.searchable').text().toLowerCase();
and then tag everything that you want to be searchable:
<table class="table table-list-search">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>address</th>
</tr>
</thead>
<tbody>
<tr>
<td class="searchable">107</td>
<td>John Doe</td>
<td>1074 example street</td>
</tr>
<tr>
<td class="searchable">100</td>
<td>Henry</td>
<td>1111 example ave</td>
</tr>
</tbody>
</table>

How can I get the corresponding table column (td) from a table header (th)?

I want to get the entire column of a table header.
For example, I want to select the table header "Address" to hide the address column, and select the "Phone" header to show the correspondent column.
<table>
<thead>
<tr>
<th id="name">Name</th>
<th id="address">Address</th>
<th id="address" class='hidden'>Address</th>
</tr>
</thead>
<tbody>
<tr>
<td>Freddy</td>
<td>Nightmare Street</td>
<td class='hidden'>123</td>
</tr>
<tr>
<td>Luis</td>
<td>Lost Street</td>
<td class='hidden'>3456</td>
</tr>
</tbody>
I want to do something like http://www.google.com/finance?q=apl (see the related companies table) (click the "add or remove columns" link)
Something like this would work -
$('th').click(function() {
var index = $(this).index()+1;
$('table td:nth-child(' + index + '),table th:nth-child(' + index + ')').hide()
});
The code above will hide the relevant column if you click on the header, the logic could be changed to suit your requirements though.
Demo - http://jsfiddle.net/LUDWQ/
With a couple simple modifications to your HTML, I'd do something like the following (framework-less JS):
HTML:
<input class="chk" type="checkbox" checked="checked" data-index="0">Name</input>
<input class="chk" type="checkbox" checked="checked" data-index="1">Address</input>
<input class="chk" type="checkbox" checked="checked" data-index="2">Phone</input>
<table id="tbl">
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td>Freddy</td>
<td>Nightmare Street</td>
<td>123</td>
</tr>
<tr>
<td>Luis</td>
<td>Lost Street</td>
<td>3456</td>
</tr>
</tbody>
Javascript:
var cb = document.getElementsByClassName("chk");
var cbsz = cb.length;
for(var n = 0; n < cbsz ; ++n) {
cb[n].onclick = function(e) {
var idx = e.target.getAttribute("data-index");
toggleColumn(idx);
}
}
function toggleColumn(idx) {
var tbl = document.getElementById("tbl");
var rows = tbl.getElementsByTagName("tr");
var sz = rows.length;
for(var n = 0; n < sz; ++n) {
var el = n == 0 ? rows[n].getElementsByTagName("th")[idx] : rows[n].getElementsByTagName("td")[idx];
el.style.display = el.style.display === "none" ? "table-cell" : "none";
}
}
http://jsfiddle.net/dbrecht/YqUNz/1/
I added the checkboxes as it doesn't make sense to bind the click to the column headers as you won't be able to toggle the visibility, only hide them.
You can do something with CSS, like:
<html>
<head>
<style>
.c1 .c1, .c2 .c2, .c3 .c3{
display:none;
}
</style>
</head>
<body>
<table class="c2 c3">
<thead>
<tr>
<th id="name" class="c1">Name</th>
<th id="address" class="c2">Address</th>
<th id="phone" class="c3">Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td class="c1">Freddy</td>
<td class="c2">Nightmare Street</td>
<td class="c3">123</td>
</tr>
<tr>
<td class="c1">Luis</td>
<td class="c2">Lost Street</td>
<td class="c3">3456</td>
</tr>
</tbody>
</table>
</body>
</html>
To hide a column, you add with Javascript the corresponding class to the table. Here c2 and c3 are hidden.
You could add dynamically the .c1, .c2,... in a style tag, or define a maximum number.
The easiest way to do this would be to add a class to each td that matches the class of the header. When you click the , it checks the class, then hides every td with that class. Since only the s in that column would hide that class, it would effectively hide the column.
<table>
<thead>
<th>Name</th>
<th>Address</th>
</thead>
<tbody>
<tr>
<td class="Name">Joe</td>
<td class="Address">123 Main St.
</tbody>
</table>
And the script something like:
$('th').click( function() {
var col = $(this).html(); // Get the content of the <th>
$('.'+col).hide(); // Hide everything with a class that matches the col value.
});
Something like that, anyway. That's probably more verbose than it needs to be, but it should demonstrate the principle.
Another way would be to simply count how many columns over the in question is, and then loop through each row and hide the td that is also that many columns over. For instance, if you want to hide the Address column and it is column #3 (index 2), then you would loop through each row and hide the third (index 2).
Good luck..
Simulating the Google Finance show/hide columns functionality:
http://jsfiddle.net/b9chris/HvA4s/
$('#edit').click(function() {
var headers = $('#table th').map(function() {
var th = $(this);
return {
text: th.text(),
shown: th.css('display') != 'none'
};
});
var h = ['<div id=tableEditor><button id=done>Done</button><table><thead><tr>'];
$.each(headers, function() {
h.push('<th><input type=checkbox',
(this.shown ? ' checked ' : ' '),
'/> ',
this.text,
'</th>');
});
h.push('</tr></thead></table></div>');
$('body').append(h.join(''));
$('#done').click(function() {
var showHeaders = $('#tableEditor input').map(function() { return this.checked; });
$.each(showHeaders, function(i, show) {
var cssIndex = i + 1;
var tags = $('#table th:nth-child(' + cssIndex + '), #table td:nth-child(' + cssIndex + ')');
if (show)
tags.show();
else
tags.hide();
});
$('#tableEditor').remove();
return false;
});
return false;
});
jQuery('thead td').click( function () {
var th_index = jQuery(this).index();
jQuery('#my_table tbody tr').each(
function(index) {
jQuery(this).children('td:eq(' + th_index + ');').each(
function(index) {
// do stuff here
}
);
}
);
});
here's a working fiddle of this behaviour:
http://jsfiddle.net/tycRW/
of course, hiding the column with out hiding the header for it will have some strange results.

Categories