How to export data from table to csv file using jquery - javascript

I'm trying to export from a data table into a CSV file. Here is my whole function. It downloads a file, but it shows the whole code for the table and not separating any of the data out. When I say whole code I mean everything within 'table /table'
function displayDataTable(index){
$("#pageOverlay").empty();
html = "<div id='volumeChartDiv'><h4>Data Table</h4><table id='dataTable' class='table table-bordered table-striped dataTable' role='grid'><thead><tr role='row'><th>header1</th><th>header2</th><th>header3</th></tr></thead><tbody><tr><td>cell1-1</td><td>cell1-2</td><td>cell1-3</td></tr><tr><td>bell2-1</td><td>bell2-2</td><td>bell2-3</td></tr><tr><td>fell3-1</td><td>fell3-2</td><td>fell3-3</td></tr></tbody></table><input type='button' value='Close' onclick='closeOverlay()'> <input type='button' id='exportDataTable' value='Export Table'></div>";
$("#pageOverlay").html(html);
// export data function
$("#exportDataTable").click(function (e) {
window.open('data:application/vnd.ms-excel,' + $('.dataTable').html());
e.preventDefault();
});
openOverlay();
}

CSV format cannot accept $('.dataTable').html() as .html() is not a structured data, it's not even data, just a silly hmtl.
You have to get data from your table, make a string representing CSV format, and download it, As you don't show your table data structure here's working demo below
$('#export').click(function() {
var titles = [];
var data = [];
/*
* Get the table headers, this will be CSV headers
* The count of headers will be CSV string separator
*/
$('.dataTable th').each(function() {
titles.push($(this).text());
});
/*
* Get the actual data, this will contain all the data, in 1 array
*/
$('.dataTable td').each(function() {
data.push($(this).text());
});
/*
* Convert our data to CSV string
*/
var CSVString = prepCSVRow(titles, titles.length, '');
CSVString = prepCSVRow(data, titles.length, CSVString);
/*
* Make CSV downloadable
*/
var downloadLink = document.createElement("a");
var blob = new Blob(["\ufeff", CSVString]);
var url = URL.createObjectURL(blob);
downloadLink.href = url;
downloadLink.download = "data.csv";
/*
* Actually download CSV
*/
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
});
/*
* Convert data array to CSV string
* #param arr {Array} - the actual data
* #param columnCount {Number} - the amount to split the data into columns
* #param initial {String} - initial string to append to CSV string
* return {String} - ready CSV string
*/
function prepCSVRow(arr, columnCount, initial) {
var row = ''; // this will hold data
var delimeter = ','; // data slice separator, in excel it's `;`, in usual CSv it's `,`
var newLine = '\r\n'; // newline separator for CSV row
/*
* Convert [1,2,3,4] into [[1,2], [3,4]] while count is 2
* #param _arr {Array} - the actual array to split
* #param _count {Number} - the amount to split
* return {Array} - splitted array
*/
function splitArray(_arr, _count) {
var splitted = [];
var result = [];
_arr.forEach(function(item, idx) {
if ((idx + 1) % _count === 0) {
splitted.push(item);
result.push(splitted);
splitted = [];
} else {
splitted.push(item);
}
});
return result;
}
var plainArr = splitArray(arr, columnCount);
// don't know how to explain this
// you just have to like follow the code
// and you understand, it's pretty simple
// it converts `['a', 'b', 'c']` to `a,b,c` string
plainArr.forEach(function(arrItem) {
arrItem.forEach(function(item, idx) {
row += item + ((idx + 1) === arrItem.length ? '' : delimeter);
});
row += newLine;
});
return initial + row;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="export">export</button>
<table class="dataTable">
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
<tr>
<td>Ernst Handel</td>
<td>Roland Mendel</td>
<td>Austria</td>
</tr>
<tr>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
</tr>
</table>
If you find any bugs, comment below, i'll fix them

An small improvement over Medet answer, assuming that you headers are in tr, all this code does is get all the columns and rows push that in plain array and exports to csv.
$('#export').click(function() {
var titles = [];
var data = [];
$('.table tr').each(function() {
data.push($(this));
});
csv_data = []
data.forEach(function(item,index){
td = item[0].children
for(i=0;i<td.length;i++){
csv_data.push(td[i].innerText)
}
csv_data.push('\r\n')
})
var downloadLink = document.createElement("a");
var blob = new Blob(["\ufeff", csv_data]);
var url = URL.createObjectURL(blob);
downloadLink.href = url;
downloadLink.download = "minicrawl.csv";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
})

If the data's not too complicated, then you can get by without jQuery:
const csvContents = [].map.call(document.getElementById('dataTable').rows,
tr => [].map.call(tr.cells, td => td.textContent).join(',')
).join('\n'))
and then download the file as with the other answers.
This won't work if the data's a bit more complicated (eg, has commas in the data), but in that case you should probably use a csv library in the first place.

Related

Wrong array method sort() logic

I Cannot understand the array method sort() logic. I had to write an eventListener for the two elements Age and Letter. By clicking on them we can sort our table by age and letter.
All works fine, but I see something strange in the sort() logic. By clicking on the Letter - table must sort by alphabet for elements in the column Letter. By clicking on the Age - table must sort by digits order for elements in the column Age. But it does not sort right.
tbody = document.getElementById('grid');
function tableSort(event) {
var target = event.target;
var action = target.getAttribute('data-type');
var arr = [].slice.call(grid.rows, 1);
var self = this;
this.number = function() {
arr.sort(function(a, b) { // sort by digits in the column "Age"
a.cells[0].innerHTML;
b.cells[0].innerHTML;
return a - b;
});
grid.appendChild(...arr);
}
this.string = function() {
arr.sort(function(a, b) { // sort by words in the column "Letter"
a.cells[1].innerHTML;
b.cells[1].innerHTML;
return a > b;
});
grid.appendChild(...arr);
}
if (action) {
self[action]();
}
}
tbody.addEventListener('click', tableSort);
th {
cursor: pointer;
}
<table id="grid">
<thead>
<tr>
<th data-type="number">Age</th>
<th data-type="string">Letter</th>
</tr>
</thead>
<tbody>
<tr>
<td>5</td>
<td>BBBBB</td>
</tr>
<tr>
<td>12</td>
<td>AAAAA</td>
</tr>
<tr>
<td>1</td>
<td>DDDDD</td>
</tr>
<tr>
<td>9</td>
<td>CCCCC</td>
</tr>
<tr>
<td>2</td>
<td>KKKKK</td>
</tr>
</tbody>
</table>
<script>
</script>
Modified your code and got it working. Here if you need it:
function tableSort(event) {
var target = event.target;
var action = target.getAttribute("data-type");
var arr = [].slice.call(grid.rows, 1);
var self = this;
this.number = function() {
arr.sort(function(a, b) {
// sort by digits in the column "Age"
return Number(a.cells[0].innerHTML) - Number(b.cells[0].innerHTML);
});
arr.forEach(function(item, index) {
grid.appendChild(item);
});
};
this.string = function() {
arr.sort(function(a, b) {
// sort by words in the column "Letter"
var str1 = a.cells[1].innerHTML;
var str2 = b.cells[1].innerHTML;
return str1.localeCompare(str2);
});
arr.forEach(function(item, index) {
grid.appendChild(item);
});
};
if (action) {
self[action]();
}
}
tbody.addEventListener("click", tableSort);
How about this stackoverflow post Sorting HTML table with JavaScript for clarification and the original external article in which I found it with a full example?
Sorting tables with VanillaJS or JQuery
Example:
/**
* Modified and more readable version of the answer by Paul S. to sort a table with ASC and DESC order
* with the <thead> and <tbody> structure easily.
*
* https://stackoverflow.com/a/14268260/4241030
*/
var TableSorter = {
makeSortable: function(table){
// Store context of this in the object
var _this = this;
var th = table.tHead, i;
th && (th = th.rows[0]) && (th = th.cells);
if (th){
i = th.length;
}else{
return; // if no `<thead>` then do nothing
}
// Loop through every <th> inside the header
while (--i >= 0) (function (i) {
var dir = 1;
// Append click listener to sort
th[i].addEventListener('click', function () {
_this._sort(table, i, (dir = 1 - dir));
});
}(i));
},
_sort: function (table, col, reverse) {
var tb = table.tBodies[0], // use `<tbody>` to ignore `<thead>` and `<tfoot>` rows
tr = Array.prototype.slice.call(tb.rows, 0), // put rows into array
i;
reverse = -((+reverse) || -1);
// Sort rows
tr = tr.sort(function (a, b) {
// `-1 *` if want opposite order
return reverse * (
// Using `.textContent.trim()` for test
a.cells[col].textContent.trim().localeCompare(
b.cells[col].textContent.trim()
)
);
});
for(i = 0; i < tr.length; ++i){
// Append rows in new order
tb.appendChild(tr[i]);
}
}
};
window.onload = function(){
TableSorter.makeSortable(document.getElementById("myTable"));
};
table thead th {
cursor: pointer;
}
<table id="myTable">
<thead>
<th data-type="string">Name</th>
<th data-type="number">Age</th>
</thead>
<tbody>
<tr>
<td>John</td>
<td>42</td>
</tr>
<tr>
<td>Laura</td>
<td>39</td>
</tr>
<tr>
<td>Fred</td>
<td>18</td>
</tr>
<tr>
<td>Bod</td>
<td>26</td>
</tr>
</tbody>
</table>

Copy a HTML table to a Word file - overwrite error

I'm trying to copy a HTML table to a Word file.
In the first all the first column copied just fine to the word table.
When the code starts to copy the second column it is overwrite the first one.
I change the index of the column --> Cell(i,0)/Cell(i,1).
Any idea why it happen?
<script>
function tab()
{
var NUMBER_OF_ROWS = 22;
var NUMBER_OF_COLUMNS = 2;
var objWord = new ActiveXObject("Word.Application");
objWord.Visible = True
Set objDoc = objWord.Documents.Add();
var objRange = objDoc.Range();
objDoc.Tables.Add (objRange, NUMBER_OF_ROWS, NUMBER_OF_COLUMNS);
var objTable = objDoc.Tables(1);
var thisTable = $(' .ms-table');
for (var i=0;i<thisTable.rows.length;i++)
{
var oCell = thisTable.rows.item(i).cells;
objTable.Cell(i,0).Range.Text = oCell.item(0).innerText;
}
for (var i=0;i<thisTable.rows.length;i++)
{
var oCell = thisTable.rows.item(i).cells;
objTable.Cell(i,1).Range.Text = oCell.item(1).innerText;
}
objTable.AutoFormat(9)
}
</script>
Please see if the below JavaScript code is helpful:
JavaScript :
if (typeof jQuery !== "undefined" && typeof saveAs !== "undefined") {
(function($) {
$.fn.wordExport = function(fileName) {
fileName = typeof fileName !== 'undefined' ? fileName : "jQuery-Word-Export";
var static = {
mhtml: {
top: "Mime-Version: 1.0\nContent-Base: " + location.href + "\nContent-Type: Multipart/related; boundary=\"NEXT.ITEM-BOUNDARY\";type=\"text/html\"\n\n--NEXT.ITEM-BOUNDARY\nContent-Type: text/html; charset=\"utf-8\"\nContent-Location: " + location.href + "\n\n<!DOCTYPE html>\n<html>\n_html_</html>",
head: "<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n<style>\n_styles_\n</style>\n</head>\n",
body: "<body>_body_</body>"
}
};
var options = {
maxWidth: 624
};
// Clone selected element before manipulating it
var markup = $(this).clone();
// Remove hidden elements from the output
markup.each(function() {
var self = $(this);
if (self.is(':hidden'))
self.remove();
});
// Embed all images using Data URLs
var images = Array();
var img = markup.find('img');
for (var i = 0; i < img.length; i++) {
// Calculate dimensions of output image
var w = Math.min(img[i].width, options.maxWidth);
var h = img[i].height * (w / img[i].width);
// Create canvas for converting image to data URL
var canvas = document.createElement("CANVAS");
canvas.width = w;
canvas.height = h;
// Draw image to canvas
var context = canvas.getContext('2d');
context.drawImage(img[i], 0, 0, w, h);
// Get data URL encoding of image
var uri = canvas.toDataURL("image/png");
$(img[i]).attr("src", img[i].src);
img[i].width = w;
img[i].height = h;
// Save encoded image to array
images[i] = {
type: uri.substring(uri.indexOf(":") + 1, uri.indexOf(";")),
encoding: uri.substring(uri.indexOf(";") + 1, uri.indexOf(",")),
location: $(img[i]).attr("src"),
data: uri.substring(uri.indexOf(",") + 1)
};
}
// Prepare bottom of mhtml file with image data
var mhtmlBottom = "\n";
for (var i = 0; i < images.length; i++) {
mhtmlBottom += "--NEXT.ITEM-BOUNDARY\n";
mhtmlBottom += "Content-Location: " + images[i].location + "\n";
mhtmlBottom += "Content-Type: " + images[i].type + "\n";
mhtmlBottom += "Content-Transfer-Encoding: " + images[i].encoding + "\n\n";
mhtmlBottom += images[i].data + "\n\n";
}
mhtmlBottom += "--NEXT.ITEM-BOUNDARY--";
//TODO: load css from included stylesheet
var styles = "";
// Aggregate parts of the file together
var fileContent = static.mhtml.top.replace("_html_", static.mhtml.head.replace("_styles_", styles) + static.mhtml.body.replace("_body_", markup.html())) + mhtmlBottom;
// Create a Blob with the file contents
var blob = new Blob([fileContent], {
type: "application/msword;charset=utf-8"
});
saveAs(blob, fileName + ".doc");
};
})(jQuery);
} else {
if (typeof jQuery === "undefined") {
console.error("jQuery Word Export: missing dependency (jQuery)");
}
if (typeof saveAs === "undefined") {
console.error("jQuery Word Export: missing dependency (FileSaver.js)");
}
}
$("a.jquery-word-export").click(function(event) {
$("#page-content").wordExport();
});
Html:
<table class="ms-table">
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
</tr>
<tr>
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
</tr>
<tr>
<td>Ernst Handel</td>
<td>Roland Mendel</td>
<td>Austria</td>
</tr>
<tr>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
</tr>
</table>
<button>tab</button>
<div class="col-xs-5">
<a class="btn jquery-word-export" href="javascript:void(0)">
<span class="word-icon">W</span>
Export as .doc
</a>
</div>
Supporting Js files:
https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js

jQuery/Javascript compare two tables against each other

I need to compare two HTML tables' rows assuming that data in first cell can be duplicated but data in second cell is always unique. I need to find whether first cell AND second cell in table1 is the same as data in first cell AND second cell in table2 for instance:
Table1:
<Table>
<tr>
<td>123</td>
<td>321</td>
</tr>
<tr>
<td>545</td>
<td>345</td>
</tr>
<tr>
<td>0</td>
<td>312</td>
</tr>
<tr>
<td>123</td>
<td>323331</td>
</tr>
</Table>
Second table:
<table>
<tr>
<td>545</td>
<td>345</td>
</tr>
<tr>
<td>545</td>
<td>3122</td>
</tr>
<tr>
<td>123</td>
<td>321</td>
</tr>
</table>
The result of this should be:
123 321 - good, do nothing
545 345 - good, do nothing
545 3122 - wrong its not in table1 <-
Here's what I've got so far...
$('#runCheck').click(function(){
var firstTable = $('#firstDiv table tr');
var secondTable = $('#secDiv table tr');
$(secondTable).each(function(index){
var $row = $(this);
var secTableCellZero = $row.find('td')[0].innerHTML;
var secTableCellOne = $row.find('td')[1].innerHTML;
$(firstTable).each(function(indexT){
if ($(this).find('td')[0].innerHTML === secTableCellZero){
if ($(this).find('td')[1].innerHTML !== secTableCellOne){
$('#thirdDiv').append("first: " + secTableCellZero + " second: " + secTableCellOne+"<br>");
}
}
});
});
});
Where am I going it wrong?
Just to clarify once again:
2nd table says :
row1 - john|likesCookies
row2 - peter|likesOranges
1st table says :
row1 - john|likesNothing
row2 - john|likesCookies
row3 - steward|likesToTalk
row4 - peter|likesApples
now it should say :
john - value okay
peter - value fail.
a lot alike =VLOOKUP in excel
Check this working fiddle : here
I've created two arrays which store values in each row of tables 1 and 2 as strings. Then I just compare these two arrays and see if each value in array1 has a match in array 2 using a flag variable.
Snippet :
$(document).ready(function() {
var table_one = [];
var table_two = [];
$("#one tr").each(function() {
var temp_string = "";
count = 1;
$(this).find("td").each(function() {
if (count == 2) {
temp_string += "/";
}
temp_string = temp_string + $(this).text();
count++;
});
table_one.push(temp_string);
});
$("#two tr").each(function() {
var temp_string = "";
count = 1;
$(this).find("td").each(function() {
if (count == 2) {
temp_string += "/";
temp_string = temp_string + $(this).text();
} else {
temp_string = temp_string + $(this).text();
}
count++;
});
table_two.push(temp_string);
});
var message = "";
for (i = 0; i < table_two.length; i++) {
var flag = 0;
var temp = 0;
table_two_entry = table_two[i].split("/");
table_two_cell_one = table_two_entry[0];
table_two_cell_two = table_two_entry[1];
for (j = 0; j < table_one.length; j++) {
table_one_entry = table_one[j].split("/");
table_one_cell_one = table_one_entry[0];
table_one_cell_two = table_one_entry[1];
console.log("1)" + table_one_cell_one + ":" + table_one_cell_two);
if (table_two_cell_one == table_one_cell_one) {
flag++;
if (table_one_cell_two == table_two_cell_two) {
flag++;
break;
} else {
temp = table_one_cell_two;
}
} else {}
}
if (flag == 2) {
message += table_two_cell_one + " " + table_two_cell_two + " found in first table<br>";
} else if (flag == 1) {
message += table_two_cell_one + " bad - first table has " + temp + "<br>";
} else if (flag == 0) {
message += table_two_cell_one + " not found in first table<br>";
}
}
$('#message').html(message);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<hr>
<table id="one">
<tr>
<td>123</td>
<td>321</td>
</tr>
<tr>
<td>545</td>
<td>345</td>
</tr>
<tr>
<td>0</td>
<td>312</td>
</tr>
<tr>
<td>123</td>
<td>323331</td>
</tr>
</table>
<hr>
<table id="two">
<tr>
<td>545</td>
<td>345</td>
</tr>
<tr>
<td>545</td>
<td>3122</td>
</tr>
<tr>
<td>123</td>
<td>321</td>
</tr>
</table>
<hr>
<div id="message">
</div>
</div>
If I understand your requirements, it would be easier to read the first table and store the couples as strings: 123/321, 545/345, etc...
Than you can read the second table and remove from the first list all the rows found in both.
What remains in the list are couples that do not match.
From purely an efficiency standpoint if you loop through the first table just once and create an object using the first cell value as keys and an array of values for second cells, you won't have to loop through that table numerous times
this then makes the lookup simpler also
var firstTable = $('#firstDiv table tr');
var secondTable = $('#secDiv table tr');
var firstTableData = {}
firstTable.each(function() {
var $tds = $(this).find('td'),
firstCellData = $tds.eq(0).html().trim(),
secondCellData == $tds.eq(1).html().trim();
if (!firstTableData[firstCellData]) {
firstTableData[firstCellData] = []
}
firstTableData[firstCellData].push(secondCellData)
})
$(secondTable).each(function(index) {
var $tds = $(this).find('td');
var secTableCellZero = $tds.eq(0).html().trim();
var secTableCellOne = $tds.eq(1).html().trim();
if (!firstTableData.hasOwnProperty(secTableCellZero)) {
console.log('No match for first cell')
} else if (!firstTableData[secTableCellZero].indexOf(secTableCellOne) == -1) {
console.log('No match for second cell')
}
});
I'm not sure what objective is when matches aren't found

Getting coordinates of table cells and comparing with different tables via Javascript

It's really easy to access to coordinates of table cells with this and this example ways. But when I'm trying to get cells and compare with another table's cell which is avaible on page, a problem occurs. Because I don't know how to compare them in same time. After many hours I tried to do this, unfortunately, still there is no luck.
In following classic tables list below, shows 2 different tables with different id numbers:
<table id="a1">
<tbody>
<tr>
<td>RED</td>
<td>GREEN</td>
<td>BLUE</td>
</tr>
<tr>
<td>YELLOW</td>
<td>PINK</td>
<td>samespothere</td>
</tr>
</tbody>
</table>
<hr>
<table id="a2">
<tbody>
<tr>
<td>BLACK</td>
<td>BROWN</td>
<td>WHITE</td>
</tr>
<tr>
<td>CYAN</td>
<td>GRAY</td>
<td>samespothereANDsomeextra</td>
</tr>
</tbody>
</table>
And also, I'm using modified version of this JS example to get location of cells. This modified version I did is not able to make compare operation. I've just edited for make it easier.
var cells = document.getElementsByTagName("td"); //For all table cells on page.
var i;
for(i = 0; i < cells.length; i++)
{
cells[i].onclick = vera;
}
function vera()
{
var cellIndex = this.cellIndex + 1;
var rowIndex = this.parentNode.rowIndex + 1;
var centra = cellIndex +","+ rowIndex; //This gives the coordinate of cell which you clicked on.
alert(centra);
}
Here is my question: I need to make a compare operation when I click on samespothere(Example text I wrote) table cell. Compare operation should be able with the same location of other table. Lets think like this: If second table cell(same location, different table) includes some of clicked cell's text(from first table), alert must show up and say "This clicked text in table id=1 cell:2row:2, matched in table id=2 cell:2row:2".
And here is the online code: http://jsfiddle.net/LujydnaL/
I think this is what you want:
function vera()
{
var cellIndex = this.cellIndex + 1;
var rowIndex = this.parentNode.rowIndex + 1;
var centra = cellIndex +","+ rowIndex; //This gives the coordinate of cell which you clicked on.
alert(centra);
// new code here
table2 = document.getElementById('a2');
rowInTable2 = table2.getElementsByTagName('tr')[rowIndex-1];
cellInTable2 = rowInTable2.getElementsByTagName('td')[cellIndex-1];
console.log(cellInTable2);
// do something with cellInTable2 now
}
window.onload = function () {
document.getElementsByTagName('table')[0].addEventListener('click', function(element) {
var rowIndex = element.target.parentElement.rowIndex;
var cellIndex = element.target.cellIndex;
var compare = document.getElementsByTagName('table')[1].rows[rowIndex].cells[cellIndex];
var myNodelist = document.querySelectorAll("td");
var i;
for (i = 0; i < myNodelist.length; i++) {
myNodelist[i].style.backgroundColor = "white";
}
compare.style.backgroundColor = "grey";
document.getElementById('alert1').innerHTML = ('CLICK => Row index = ' + rowIndex + ', Column index = ' + cellIndex);
document.getElementById('alert2').innerHTML = ('COMPARE = ' + compare.innerHTML)
}, false);
}
tr, th, td {
padding: 0.2rem;
border: 1px solid black
}
table:hover {
cursor: pointer;
}
<table>
<tbody>
<tr>
<td>a11</td>
<td>a12</td>
<td>a13</td>
</tr>
<tr>
<td>a21</td>
<td>a22</td>
<td>a23</td>
</tr>
</tbody>
</table>
<p id="alert1"></p>
<hr>
<table>
<tbody>
<tr>
<td>b11</td>
<td>b12</td>
<td>b13</td>
</tr>
<tr>
<td>b21</td>
<td>b22</td>
<td>b23</td>
</tr>
</tbody>
</table>
<p id="alert2"></p>

Sum column totals depending on text of another column using jQuery

I have this code that I use to calculate totals in specific columns based on the text in a different column. It works just fine, but I'm learning, so I would like to know if there is way to consolidate this code. As you can see I run a "each()" twice, once for each column. The first each check for "A" in the first column, then goes to the second column and adds the rows that meet the criteria. Similar on the second column, just that it looks for "B" and add columns 3. Is there a way to run the each function only once and check both column at the same time?
JS:
//Second Column
var total = 0;
$("#theTable tr:contains('A') td:nth-of-type(2)").each(function () {
var pending = parseInt($(this).text());
total += pending;
});
$("#theTable tfoot tr:last-of-type td:nth-of-type(2)").text(total);
//Third Column
var total2 = 0;
$("#theTable tr:contains('B') td:nth-of-type(3)").each(function () {
var pending2 = parseInt($(this).text());
total2 += pending2;
});
$("#theTable tfoot tr:last-of-type td:nth-of-type(3)").text(total2);
HTML:
<table id="theTable">
<thead>
<tr>
<th>MONTH</th>
<th>PENDING</th>
<th>DENIED</th>
</tr>
</thead>
<tbody></tbody>
<tr>
<td>A</td>
<td>2</td>
<td>4</td>
</tr>
<tr>
<td>B</td>
<td>1</td>
<td>3</td>
</tr>
<tr>
<td>A</td>
<td>3</td>
<td>2</td>
</tr>
<tr>
<td>C</td>
<td>3</td>
<td>2</td>
</tr>
<tr>
<td>A</td>
<td>2</td>
<td>2</td>
</tr>
<tr>
<td>B</td>
<td>4</td>
<td>2</td>
</tr>
<tfoot>
<tr>
<td>TOTALS:</td>
<td></td>
<td></td>
</tr>
</tfoot>
This may look simple for some of you, but again, I'm just learning some JS now.
Thanks!
You could try something like this:
var total = {A:{row:1,t:0},B:{row:2,t:0}};
$('#theTable tr').each(function() {
$row = $(this);
$.each(total, function(key, col) {
rowFil = $row.filter(':contains("' + key + '")');
col.t += (rowFil) ? +rowFil.find('td:eq(' + col.row + ')').text() : 0;
});
});
$("#theTable tfoot tr:last td:eq(1)").text(total.A.t);
$("#theTable tfoot tr:last td:eq(2)").text(total.B.t);
someThing of this sort might Help ...
var trs = $('#'+tblID).find('tr');
var total1 = 0;
var total2 = 0;
$.each(trs, function(k, v) {
if ($(v).text == "A"){
total1 += parseInt($(v).parent('tr').find('td:eq(2)').text());
}
if ($(v).text == "B"){
total2 += parseInt($(v).parent('tr').find('td:eq(3)').text())
}
});
Here is another approach - I've summed up all statistics for all possible values:
var totals = [];
$('#theTable tbody tr').each(function(e) {
var tds= $(this).find('td');
var index = $(tds[0]).text();
var pending = parseInt($(tds[1]).text(), 10);
var denied = parseInt($(tds[2]).text(), 10);
if (totals[index] == undefined)
totals[index] = { Pending: 0, Denied: 0 };
totals[index].Pending += pending;
totals[index].Denied += denied;
});
for (var key in totals)
$('#theTable tfoot').append('<tr><td>'+key+'</td><td>'+
totals[key].Pending+'</td><td>'+totals[key].Denied+'</td></tr>');
I've also updated markup a little, here is jsfiddle. The code may be not so pretty, but doing more stuff and can be refactored.
Creating a second table with the sums makes it easier to analyse the data.
SOLUTION
JS
//make a list of unique months
var months = [];
$('#theTable tr td:nth-of-type(1)').each(function(){
var month = $(this).text();
if(months.indexOf(month) < 0) months.push(month);
});
console.log('months', months);
//make a data structure with sums
var data = {};
var tr = $('#theTable tr');
$.each(months, function(){
var month = this;
data[month] = {
pending: 0,
denied: 0
};
tr.each(function(){
var ch = $(this).children();
var m = $(ch[0]).text();
var pending = $(ch[1]).text();
var denied = $(ch[2]).text();
if(m == month) {
data[month].pending += parseInt(pending);
data[month].denied += parseInt(denied);
}
});
});
console.log('data', data);
//make a table with the data
var table = $('<table>');
table.append($('<tr>'+
'<th>MONTH</th>'+
'<th>PENDING</th>'+
'<th>DENIED</th>'+
'</tr>'));
$.each(data, function(month){
table.append($('<tr>'+
'<td>'+month+'</td>'+
'<td>'+data[month].pending+'</td>'+
'<td>'+data[month].denied+'</td>'+
'</tr>'));
});
$('body').append(table);

Categories

Resources