I'm trying to use tablesorter on a dynamic HTML table. When the data in the table changes, and I try to sort, the table messes up; it adds the previous data and the current data and combines them both into one table, and it is also sorting other tables!! How can I make it so when the table changes, tablesorter will update? I'm populating the table from a .csv using jQuery, and the table is dynamic, because the HTML page the table is in has multiple file names, if you click on one, the data from that file will be loaded to that table
I'm using multiple tables, and one tablesorter, but here's one of my tables:
<div id="origtable">
<table border="1" id="table_side">
<thead>
<tr>
<th>Origin <br> Country</th>
<th>Count</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
Here's my tablesorter:
/* tried this at first because I'm waiting for data from .csv file to populate table
setInterval(function(){sortStuff()},1000);
function sortStuff(){
$("table").tablesorter({
sortList: [[1,1]]
});
$("table").trigger("update");
}
*/
$(document).ready(function(){
$("table").tablesorter({
sortList: [[0,1]]
});
});
$("table").on( "click", function() {
$("table").trigger("update");
});
EDIT 1:
jquery function used to populate html table after reading from .csv (this jquery code is in a seperate .js file)
function populateTableCounts(rowkey, tablename, hashdata)
{
var rowhtml = "";
$.each(hashdata, function (key, value) {
key = key.replace(/-/g, ' / ');
key = key.replace(/:/g, ' , ');
var rowdata=countrow.replace('$row_key', key);
rowdata=rowdata.replace('$row_val', value);
//add row <tr> to var rowhtml
rowhtml += rowdata;
});
//append populated rowhtml to TBODY
$('#' + tablename + ' tbody').append(rowhtml);
}
Ignore my comment is trigger("update") the function you need, but check if this code works
$(document).ready(function(){
$("table").tablesorter({
sortList: [[0,1]]
});
$("table").click(function(){ $("table").trigger("update"); });
});
EDIT
If you are using get to obtain csv data you need something like this:
$.get("your/csv/file.csv",function(csv){
//... code that handle your csv and put into table
//...
//AT END UPDATE TABLE
$("table").trigger("update");
});
EDIT2
function populateTableCounts(rowkey, tablename, hashdata)
{
var rowhtml = "";
$.each(hashdata, function (key, value) {
key = key.replace(/-/g, ' / ');
key = key.replace(/:/g, ' , ');
var rowdata=countrow.replace('$row_key', key);
rowdata=rowdata.replace('$row_val', value);
//add row <tr> to var rowhtml
rowhtml += rowdata;
});
//append populated rowhtml to TBODY
$('#' + tablename + ' tbody').append(rowhtml);
//You can do this
$('#' + tablename).trigger("update");
//or this if you want $('table').trigger('update');
}
You can do this things without problem, you need to take care that the elements must be loaded so execute all on $(document).ready.
There is no problem if the js script is on another file.
Related
I have a dynamically generated CSV file from another vendor that I am puling in and need to show in a table on my site. The problem is I need to be able to manipulate the data from the CSV so it can show the corrected values in the html table. In the end I need the HTML table to just display the Products, not the Mixed Sets.
I am using jquery and the papaparse library to get the data and parse it in a table in html. My codepen is here:
https://codepen.io/BIGREDBOOTS/pen/YQojww
The javascript pulls the initial csv values and display in a table, but I can't figure out how to to add together the values. If there is a better way of going about this, like converting the CSV to some other form of data like JSON, That is fine too.
My CSV looks like this:
product_title,product_sku,net_quantity
Product 1,PRD1,10
Product 2,PRD2,20
Product 3,PRD3,30
Mixed Set 1,MIX1,100
Mixed Set 2,MIX2,50
Mixed Set 3,MIX3,75
The Javascript I am using is:
function arrayToTable(tableData) {
var table = $('<table></table>');
$(tableData).each(function (i, rowData) {
var row = $('<tr class="rownum-' + [i] + '"></tr>');
$(rowData).each(function (j, cellData) {
row.append($('<td class="' + [i] + '">'+cellData+'</td>'));
});
table.append(row);
});
return table;
}
$.ajax({
type: "GET",
url: "https://cdn.shopify.com/s/files/1/0453/8489/t/26/assets/sample.csv",
success: function (data) {
$('body').append(arrayToTable(Papa.parse(data).data));
}
});
My rules for the mixed set:
Mixed Set 1 should add 100 to Product 1 and Product 2.
Mixed Set 2 should add 50 to Product 2 and Product 3.
Mixed Set 3 should add 75 to Product 1, Product 2 and Product 3.
I'd like to end up with Just the products output, and the correct numbers added to the formula.
The end result would be a table with Product 1 = 185, Product 2 = 245, and Product 3 = 155.
While it would be even better if the top THEAD elements were in a "th", It's fine if that is too complicated.
<table>
<tbody>
<tr class="rownum-0">
<td class="0">product_title</td>
<td class="0">product_sku</td>
<td class="0">net_quantity</td>
</tr>
<tr class="rownum-1">
<td class="1">Product 1</td>
<td class="1">PRD1</td>
<td class="1">185</td>
</tr>
<tr class="rownum-2">
<td class="2">Product 2</td>
<td class="2">PRD2</td>
<td class="2">245</td>
</tr>
<tr class="rownum-3">
<td class="3">Product 3</td>
<td class="3">PRD3</td>
<td class="3">155</td>
</tr>
</tbody>
</table>
Without knowing the size of the dataset you're working with, I suggest you first iterate through all the CSV dataset in order to populate a list of products with the correct values, and then iterate again on that to populate your HTML table:
function datasetToMap(data) {
var ret = {};
//Initialize a map with all the product rows
$(data).each(function(index, row) {
if(row[0].startsWith("Product")) {
ret[row[1]] = row; //Using the SKU as the key to the map
}
});
//Apply your mixed sets rules to the elements in the ret array
$(data).each(function(index, row) {
if(row[1] === "MIX1") {
ret["PRD1"][2] += 100;
ret["PRD2"][2] += 100;
}
//Do the same for Mixed sets 2 and 3
});
return ret;
}
function appendMapToTable(map) {
var $table = $('#my-table');
Object.keys(map).forEach(function(key, i) {
var rowData = map[key];
var row = $('<tr class="rownum-' + [i] + '"></tr>');
$(rowData).each(function (j, cellData) {
row.append($('<td class="' + [j] + '">'+cellData+'</td>'));
});
$table.append(row);
});
}
$.ajax({
type: "GET",
url: "https://cdn.shopify.com/s/files/1/0453/8489/t/26/assets/sample.csv",
success: function (data) {
appendMapToTable(datasetToMap(Papa.parse(data).data));
}
});
Note that this expects a table with id my-table to be already present in your HTML: you could manually parse the first row of your CSV data to add the table headings.
Also note that if your CSV dataset is very big this is definitely not an optimal solution, since it requires iterating through all its lines twice and then iterating again through all the list built with computed values.
I am performing some ASP.NET gridview conversions using the datatables.net plug-in. The answer to why I am doing this is more involved and can be debated. However, I need some help with one of the issues I am running into.
Using Javascript to convert the gridview on the page was actually quite simple and works well. The major issue is that I want to have a fixed 'total' row (footer) within the body of the datatable so that it remains responsive just like the rest of the table.
I have attempted to add a footer using the code-behind, and I can populate that footer with total data, but it is not responsive with the rest of the table. I am assuming because the <tfoot> is outside of the <tbody>.
Using javascript, I have successfully added a new datatable row and I can output the data to the console, but I am unable to populate the added row with the object data.
Javascript:
var sum;
$(document).ready(function () {
var table = $('#cphPage_gvTaxColl').DataTable();
//convert string to int
var intVal = function (i) {
var j = $("<span/>");
var txt = j.html(i).text();
// alert('txt :' + txt);
var myVal = typeof txt === 'string' ?
parseFloat(txt.replace(/[^\d.-]/g, '')) :
typeof txt === 'number' ?
i : 0;
return myVal || 0;
};
//format integer as currency
var formatSum = function (myVal) {
return accounting.formatMoney(myVal, {
symbol: "$",
precision: 2,
thousand: ",",
decimal: ".",
format: {
pos: "%s %v",
neg: "%s (%v)",
zero: "%s 0.00"
}
});
};
//add total row and determine index
table.row.add(['GRAND TOTAL']).draw();
var total_row = (table.row().count() + 1);
var total_col = (table.row(total_row).column().count + 1);
//alert
console.log('total row: ' + total_row);
//loop columns
table.columns('.sum').every(function () {
sum = this
.data()
.reduce(function (a, b) {
console.log('adding ' + intVal(a) + ' and ' + intVal(b));
return intVal(a) + intVal(b);
});
//alert
console.log('sum: ' + sum);
console.log('column row 2 val: ' + this.data().row([2]));
$(this.cell.node( total_row )).html(
formatSum(sum)
);
});
});
How do I present the object data within the datarow?
I am also receiving the following error message, and I am not certain which parameter is missing ( the 2nd and 3rd columns are null ):
Error message
I have included a screenshot with the console data, and if you need it I can provide the .aspx markup:
Page + cosole log output
I'm still learning the ins-and-outs of this stuff. Any guidance you can provide is greatly appreciated.
Thanks in advance!
Here is my solution:
The html-table for datatables should have <tfoot>
Something like this:
<table id='table'>
<tbody>
<tr><td></td></tr>
</tbody>
<tfoot>
<tr><td></td></tr>
</tfoot>
</table>
Define footerCallback field
Datatables initialization:
$('#table').dataTable({
...
"footerCallback": _footerDrawn
...
});
footerCallback:
I use server-side data, so my source of data for footer is just another field of of ajax-response:
_footerDrawn: function( row, data, start, end, display ) {
var table = $('#table').dataTables();
var json = table.api().ajax.json();
// assign values to each cell of the footer from json.total array
$.each( table.api().columns().indexes(), function( index ) {
$( table.api().column( index ).footer() ).html( json.total[index] );
});
}
}
json.total contains array of string to print in footer row
Here is my jsfiddle work. I have some issues with generating table without any html. I have one json object that i need to itterate and to put keys and values in table like:
<tr> <td> key </td> <td> key </td> ... </tr>
<tr> <td> val </td> <td> val </td> ... </tr>
I tried first to generate the table like this one, but next i wanted to use jquery version of creating td's and tr's, but the all keys and values were appended in only one td and actually this is not what i want.
You have to loop through keys the first time to set the head of table, after that make the rows inside each and append every one to the table to make the body of your table, check example code bellow :
$.ajax({
type : "POST",
dataType : "json",
url : '/echo/json/',
data : { json: JSON.stringify( jsonData ) },
success : function(data){
var jsn = $(data.markers);
//First time append table head
if(!header)
{
var row = $('<tr></tr>');
for(key in jsn[0])
{
row.append('<th>'+key+'</th>');
}
table.append(row);
header = true;
}
for ( var i = 0; i < jsn.length ; i++){
var row = $('<tr></tr>');
$.each(jsn[i], function(key,val)
{
row.append('<td>'+val+'</td>');
});
table.append(row);
}
}
});
Take a look at Working fiddle.
Hope this helps.
The issue was in the scope of the col and row variables. You must reassign them in the loop, or redeclare.
Here is the updated jsfiddle. By the way there is no need to use for loop. In jQuery it is enough to use the $.each function on the object.
From here you can see how to create table structure and replace the key and val with the actual data you need.
You need to create new row object in each for iteration:
for (var mrksIndex = 0, mrksLength = jsn.length; mrksIndex <= mrksLength; ++mrksIndex) {
row = $("<tr/>");
$.each(jsn[mrksIndex], function (key, val) {
col = $("<td/>");
col.append(key);
row.append(col);
table.append(row);
});
}
Demo: https://jsfiddle.net/6dw2u8uz/15/
Background Information
I have two tables, one that is a list of available users, called "users" and the other one called "selected_users". When a row from the users table is clicked on, the app add / removes record from the selected_users table
<table id=users>
<tr class="odd" role="row" id="row_89"><td>89</td><td>John Doe</td><td>23819</td><td>mm2#yahoo.com</td></tr>
<tr class="even" role="row" id="row_90"><td>90</td><td>John Doe</td><td>23819</td><td>36338</td></tr>
<tr class="odd" role="row" id="row_91"><td>91</td><td>Jane Doe</td><td>23820</td><td>jane#yahoo.com</td></tr>
<tr class="even" role="row" id="row_92"><td>92</td><td>Jane Doe</td><td>23820</td><td>28519</td></tr>
<tr class="odd" role="row" id="row_93"><td>93</td><td>Jim Bob</td><td>23801</td><td>jbob#yahoo.com</td></tr>
</table>
<table id=selected_users class="table table-condensed table-bordered" width="80%">
<tr class="info"><td colspan="4"><b>Selected Users:</b></td></tr>
</table>
Question
I need to change the existing logic so that when a row in the available users list is selected, all other rows in the available users table that has a matching "pid" (which is the 3rd column) should be added to the selected_users table.
This is the code that is triggered when someone clicks on the available users table:
$('#users tbody').on('click', 'tr', function () {
var id = this.id;
var tr;
tr=$('<tr/>');
var index = $.inArray(id, selected);
if ( index === -1 ) {
selected.push( id ); //select/highlight in list of available users.
// Find td's inside this tr and add to selected_users table
var tds = $(this).find('td');
tr.append("<td>" + tds.eq(0).text() + "</td>");
tr.append("<td>" + tds.eq(1).text() + "</td>");
tr.append("<td>" + tds.eq(2).text() + "</td>");
tr.append("<td>" + tds.eq(3).text() + "</td>");
tr. attr('id', id.substring(4));
$('#selected_users').append(tr);
//loop through the avail users table and select all records with the same p number.
$("users td").each(function(i,o){
// new code goes here
}
} else {
selected.splice( index, 1 ); //deselect from list of avail users
//remove matching record from selected_users table.
var record_id = id.substring(4);
var rowtodelete = document.getElementById(record_id);
rowtodelete.parentNode.removeChild(rowtodelete);
}
$(this).toggleClass('selected');
} );
} );
What I have so far
I'm thinking of adding code like this (pseudo code) in the section with the comment "new code goes here"
//loop through the avail users table and select all records with the same pager number.
$("users tr").each(function(){
$(this).find('td ....
});
I'm not sure how to do a find to see if the third column matches what I have in tds.eq(2).text()
Any suggestions would be appreciated
EDIT 1
This is what I have so far:
//2015.06.11 - find and add all other rows with matching p number
var thisTR = $(this);
console.log(thisTR);
//select all siblings with same value in third column
thisTR.siblings().filter(function() {
console.log($('td',this).eq(2).text() );
//console.log($('td', thisTR).eq(2).text());
if ($('td',this).eq(2).text() == $('td', thisTR).eq(2).text() ) {
console.log("i found a match");
console.log("what is the row for: " + $('td',this).eq(2).text());
};
});
I just need a way identify the row where the matching td was found, and then do something similar to what I'm already doing to add a row to selected_users:
var tr;
tr = "";
... find the row and then...
tr.append("" + tds.eq(0).text() + "");
tr.append("" + tds.eq(1).text() + "");
tr.append("" + tds.eq(2).text() + "");
tr.append("" + tds.eq(3).text() + "");
tr. attr('id', id.substring(4));
$('#selected_users').append(tr);
Here is what you can use - .filter( function )
//save a reference of the current row
var thisTR = $(this);
//select all siblings with same value in third row
thisTR.siblings().filter(function() {
return $('td',this).eq(2).text() == $('td', thisTR).eq(2).text();
})
//Iterate through them and do what needs to be done.
.each(function() {
//do something
//here 'this' refers to tr (matched row)
//$('td', this) should give you all the tds in 'this' row
});
My suggestion is to add the user ID to the elements using a data- custom attribute so you can easily access them with a selector.
For example, notice the data-uid attribute below:
<tr class="odd" role="row" id="row_89" data-uid="23819"><td>89</td><td>John Doe</td><td>23819</td><td>mm2#yahoo.com</td></tr>
With that in place, grabbing all the relevant rows is easy:
rows = $('#users tr[data-uid=' + uid + ']');
// ...
My function is pulling information from an api and then putting it into the table. For some reason this function is not working.
this is my function:
function getPayInfo(socCode) {
var apiurl = "http://api.lmiforall.org.uk/api/v1/ashe/estimatePay?soc=";
var apicall = apiurl + socCode;
$.get(apicall, function(data) {
$("#Pay tbody").html("");
$.each(data.years, function(i, e) {
var tablerow = $("<tr></tr>");
tablerow.append("<td>" + e.year + "</td>");
tablerow.append("<td>" + e.estpay + "</td>");
$("#Pay tbody").append(tablerow);
});
});
}
and this is the table I am putting it into:
<div class="well table table-stripped">
<h4>Pay Information</h4>
<h5>Pounds per Week</h5>
<table id="Pay">
<thead>
<tr>
<th>Year</th>
<th>Estimate Pay</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
I expected it to return a year and data value into the table. if you take the url in the function and add a certain 4 figure value (the socCode) (e.g. 5113) to the end it will give the data online this should then be returned to the table body.
Have you debugged/examined the data structure inside your $.get callback? It looks to me that your access method is incorrect. When I access your example url, I get the following data back:
{
"soc":5113,
"series":[
{
"year":2012,
"estpay":340
}
]
}
I think you want your iterator to be this instead:
// there is no data.years
$.each(data.series, function(i, e) {
...
This should make your e param be of the form {year: 2012, estpay: 340}, which appears to be what you want to interpret it as.