I have a table which takes data from an array. My problem is that I do not know how to make it so that the cell takes the whole row if the objects in the array have a value of zero. If it has a value greater than zero, 2 cells will be displayed one with an item name and another with its value. Any help is much appreciated.
//breaks loop if x is == to counters array
if (this.state.counters.length == x) {
break;
}
const info = this.state.counters[x]["text"];
const quantity = this.state.counters[x]["value"];
console.log(info, quantity);
//creates rows based on input
var table = document.getElementById("myList");
var row = table.insertRow(1);
document.getElementById("thTitle").style.maxWidth = "100px";
if (quantity <= 0) {
var itemCell = row.insertCell(0);
itemCell.innerHTML = info;
} else {
var itemCell = row.insertCell(0);
var quantityCell = row.insertCell(1);
itemCell.innerHTML = info;
itemCell.style.minWidth = "100px";
quantityCell.innerHTML = quantity;
}
This is my output:
put this in:
if (quantity <= 0) {
var itemCell = row.insertCell(0);
itemCell.innerHTML = info;
// this line
itemCell.setAttribute('colspan', '2');
}
there is the attribute colspan to td tag that the number is the number of rows he stretched on.
<table>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
<tr>
<td colspan="2">Sum: $180</td>
</tr>
</table>
//In Js just add
itemCell.setAttribute('colspan', '2');
when the quantity <= 0
I need to sum values in a two column table, where for each row if col2 is not blank, add it to the total, else instead add col1. Then publish the total to a div
Below is what I've tried but it outputs blank.
var table = document.getElementById("PLTable");
var cost_est = document.getElementsByClassName("cost_estimate");
var act_cost = document.getElementsByClassName("act_cost");
var sum2 = 0;
for (var i = 0, row; row = table.rows[i]; i++) {
if (act_cost[i].innerText>0) {
sum2 += act_cost[i].innerText;
}
else {
sum2 += cost_est[i].innerText;
}
}
document.getElementById("cost_projected_total").innerHTML = sum2
<!--HTML data looks like this:-->
<table id="PLTable">
<thead>
<tr>
<th>cost estimate</th>
<th>cost actual</th>
</tr>
</thead>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost"></td>
</tr>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost">50</td>
</tr>
</table>
<div id="cost_projected_total">
</div>
Correct output should be sum2 = 150 & that result should be output inside the div.
Any ideas?
There are some points to address in your code.
I will try to summarize what was wrong and how it should be change:
table.rows actually loops the head as well, so your index would go out of bounds.
innerText returns a text, so you first need to conver that value to a Number first, otherwise it will concatenate the strings.
So, basically, what I did to keep your code as it currently was is:
added a tbody
changed table.rows to the count of the tbody rows.
Acquired both numeric values of the looped items.
Below is the working code with the mentioned changes and fixes, it could've been way shorted, I just want to keep the code as close to your so that you can understand where and what was wrong, without necessarely relying on an optimal solution.
var table = document.getElementById("PLTable");
var tbody = table.getElementsByTagName('tbody')[0];
var cost_est = document.getElementsByClassName("cost_estimate");
var act_cost = document.getElementsByClassName("act_cost");
var sum2 = 0;
for (var i = 0; i < tbody.getElementsByTagName('tr').length; i++) {
var row_act_cost = Number(act_cost[i].innerText);
var row_cost_est = Number(cost_est[i].innerText);
if (row_act_cost > 0) {
sum2 += row_act_cost;
}
else {
sum2 += row_cost_est;
}
}
document.getElementById("cost_projected_total").innerHTML = sum2;
<table id="PLTable">
<thead>
<tr>
<th>cost estimate</th>
<th>cost actual</th>
</tr>
</thead>
<tbody>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost"></td>
</tr>
<tr>
<td class = "cost_estimate">100</td>
<td class = "act_cost">50</td>
</tr>
</tbody>
</table>
<div id="cost_projected_total">
</div>
Loop through act_cost and check if the text in each cell is a valid and > 0 number then add it to sum2 otherwise add the cost_est at that index to sum2.
const table = document.getElementById("PLTable"),
cost_est = document.querySelectorAll(".cost_estimate"),
act_cost = document.querySelectorAll(".act_cost"),
total = document.getElementById("cost_projected_total");
let sum2 = 0;
/** loop through the "act_cost" (2nd column) **/
/**
* el: current td from "act_cost".
* i: its index in "act_cost"
**/
act_cost.forEach((el, i) => sum2 += +el.textContent > 0 ? +el.textContent:+cost_est[i].textContent);
/** "+" transforms the text into a number if possible **/
total.textContent = 'Total: ' + sum2;
<table id="PLTable">
<thead>
<tr>
<th>cost estimate</th>
<th>cost actual</th>
</tr>
</thead>
<tr>
<td class="cost_estimate">100</td>
<td class="act_cost"></td>
</tr>
<tr>
<td class="cost_estimate">100</td>
<td class="act_cost">50</td>
</tr>
</table>
<div id="cost_projected_total"></div>
I have an html table that I want to read from and create a new table underneath it from reading the first table. The first table looks like this:
ID | Value
100 | 3
200 | 2
400 | 7
100 | 4
and should output this
ID | Total
100 | 7
200 | 2
400 | 7
I'm having trouble creating the new rows after the first row and adding them based on ID, heres what I have so far
var id = document.getElementByID("total");
var td = document.createElement('td');
var eleName = document.getElementsByName('initValue');
var total = 0;
for (var i = 1; i < eleName.length; i++) {
total += parseInt(eleName[i].value);
}
td.textContent = total;
id.appendChild(td);
Right now its just adding all the values
The ID can only increase by 100 and can have more than just 100-400 and more entries. The inital table is made with php
original table html
<table>
<tr><th>ID</th><th>Value</th></tr>
<tr><td name="itin" id="itin">100</td><td id="initValue" name="initValue">3</td></tr>
<tr><td name="itin" id="itin">200</td><td id="initValue" name="initValue">2</td></tr>
<tr><td name="itin" id="itin">400</td><td id="initValue"name="initValue">7</td></tr>
<tr><td name="itin" id="itin">100</td><td id="initValue" name="initValue">4</td></tr>
</table>
As a few people have said in the comments an element's ID, <el id="something">, must be unique and there cannot be any duplicates of it on the page. If you want to "group" similar elements use a class.
For solving your problem, since the value of your ID is is a direct sibling we only need one selector to get the ID and Value:
const itin = document.querySelectorAll('[name="itin"]');
With this we can loop over every ID element, name="itin", and get the value with el.nextElementSibling.textContent. We're going to be keeping track of our IDs and Values in an object since javascript doesn't have key/value pair arrays: let values = {}.
We use .nextElementSibling to ignore white spaces and only get the next element.
We check if values already has a record of our ID with hasOwnProperty, if it does, we add the values together, if not we create a property in values with our ID and give it a value:
if (values.hasOwnProperty(inner)) {
values[inner] = values[inner] += parseInt(next);
} else {
values[inner] = parseInt(next);
}
Next we create a second loop to iterate over all properties in values and build our new table with that and the rest is pretty straight forward.
The two loops could likely be combined into one with a bit more logic to search for matching IDs.
const itin = document.querySelectorAll('[name="itin"]');
let values = {};
itin.forEach(item => {
const inner = item.textContent;
let next = null;
/* For direct sibling use this */
//const next = item.nextElementSibling.textContent;
/* For an unknown sibling use this */
for ( let a = 0; a < item.parentElement.children.length; a++ ) {
const n = item.parentElement.children[a];
if ( n.getAttribute('name') === 'initValue') {
next = n;
}
}
next = next.textContent;
/****/
if (values.hasOwnProperty(inner)) {
values[inner] = values[inner] += parseInt(next);
} else {
values[inner] = parseInt(next);
}
});
const table_two = document.querySelector('.table-two tbody');
for (let prop in values) {
const val = values[prop];
let tr = document.createElement('tr');
let td1 = document.createElement('td');
let td2 = document.createElement('td');
td1.innerHTML = prop;
td2.innerHTML = val;
tr.appendChild(td1);
tr.appendChild(td2);
table_two.appendChild(tr);
}
<table>
<tr>
<th>ID</th>
<th>Value</th>
</tr>
<tr>
<td name="itin">100</td>
<td name="initValue">3</td>
</tr>
<tr>
<td name="itin">200</td>
<td name="initValue">2</td>
</tr>
<tr>
<td name="itin">400</td>
<td name="initValue">7</td>
</tr>
<tr>
<td name="itin">100</td>
<td name="initValue">4</td>
</tr>
</table>
<table class="table-two">
<thead>
<tr>
<th>ID</th>
<th>Value</th>
</tr>
</thead>
<tbody></tbody>
</table>
An entirely javascript solution based on what you have provided is available on this jsfiddle
var tds = document.getElementsByName("itin");
var tdDict = {};
var keys = [];
for(var i=0;i<tds.length;i++){
var tdId = tds[i];
var tdVal = tds[i].nextSibling;
if(tdId.textContent in tdDict){
var curTotal = tdDict[tdId.textContent];
var newTotal = curTotal + parseInt(tdVal.textContent);
tdDict[tdId.textContent] = newTotal;
}
else{
tdDict[tdId.textContent] = parseInt(tdVal.textContent);
keys.push(tdId.textContent);
}
}
var totalDiv = document.getElementById("totals");
var totalTable = document.createElement("table");
totalDiv.append(totalTable);
var hrow = document.createElement("tr");
var idHeader = document.createElement("th");
idHeader.textContent = "ID";
var totalHeader = document.createElement("th");
totalHeader.textContent = "Total";
totalTable.append(hrow);
hrow.append(idHeader);
hrow.append(totalHeader);
for(var i=0;i<keys.length; i++){
var newRow = document.createElement("tr");
var idVal = keys[i];
var valVal = tdDict[idVal];
var idValTd = document.createElement("td");
idValTd.textContent = idVal;
var valValTd = document.createElement("td");
valValTd.textContent = valVal;
newRow.appendChild(idValTd);
newRow.appendChild(valValTd);
totalTable.appendChild(newRow);
}
<table>
<tr><th>ID</th><th>Value</th></tr>
<tr><td name="itin" id="itin">100</td><td id="initValue" name="initValue">3</td></tr>
<tr><td name="itin" id="itin">200</td><td id="initValue" name="initValue">2</td></tr>
<tr><td name="itin" id="itin">400</td><td id="initValue"name="initValue">7</td></tr>
<tr><td name="itin" id="itin">100</td><td id="initValue" name="initValue">4</td></tr>
</table>
<div id="totals">
</div>
I have a table. I'd like to compare participants. If participant have several result points in the table, the script has to return sum of all participant's results. And so on for every participant.
The table is generated from database (".$row["pnt"]."".$row["station"]."".$row["res"]."):
Participant Station Points
aa Some1 1
dd Some1 2
aa sm2 3
dd sm2 4
bb sm3 5
ee sm3 6
For example I've to recieve such a new table:
aa - 4,
dd - 6,
bb - 5,
ee - 6
I've tried to do so:
$(document).ready(function () {
$("body").click(function () {
var rows = $("tbody tr");
var jo = [];
for (var i = 0; i < rows.length; i++) {
for (var j = 1; j <= rows.length; j++) {
var pnt1 = $(rows[i]).find(".pnt").html();
var stations1 = $(rows[i]).find(".station").html();
var pntR1 = $(rows[i]).find(".res").html();
if (pnt1 == $(rows[j]).find(".pnt").html()) {
pntR1 = parseInt(pntR1);
pntR2 = parseInt($(rows[j]).find(".res").html());
jo.push(pnt1, pntR1, pntR2);
break;
}
}
}
console.log(jo);
});
});
But I understood that I'm on a wrong way. Please, help me. I really appreicate if some one could help me on this issue.
Updated after comments:
<table id="pntsRes">
<thead>
<tr>
<th>Участники</th>
<th>Баллы</th>
</tr>
</thead>
<tbody>
<tr><td class="pnt">aa</td><td class="station">AES</td><td class="res">1</td></tr><tr><td class="pnt">dd</td><td class="station">AES</td><td class="res">2</td></tr>
<tr><td class="pnt">aa</td><td class="station">Science</td><td class="res">3</td></tr>
<tr><td class="pnt">dd</td><td class="station">Science</td><td class="res">4</td></tr><tr><td class="pnt">bb</td><td class="station">Аэродром</td><td class="res">5</td></tr>
<tr><td class="pnt">ee</td><td class="station">aeroport</td><td class="res">6</td></tr></tbody>
</table>
First, I would consider breaking your solution into three functions - one to extract the data from the HTML (which is a questionable practice in itself), one to transform the data, and one to output the new table. This way, your code is much more maintainable.
function getData() {
var rows = $("tbody tr");
var data = [];
rows.each(function(idx, row){
var pnt = row.find('.pnt').html(),
station = row.find('.station').html()),
res = parseInt(row.find('.res').html());
data.push(pnt, station, res);
});
}
Then I would consider something like this for the second method
// Pass the output from getData() into processData()
function processData(data){
var groupedKeys = {};
var groupedData = data.map(function(datum){
var name = datum[0];
var value = datum[2];
groupedKeys[name] = (groupedKeys[name] || 0) + (value || 0);
});
var transformedData = [];
Object.keys(groupedKeys).forEach(function(key){
transformedData.push([key, groupedKeys[key]]);
});
return transformedData;
}
The last method of course would need to be implemented by yourself, there's a ton that could be improved here, but it could be a good start.
I used an associative array (which is just an object in JavaScript) shown below:
http://jsfiddle.net/a5k6w300/
Changes I made:
var jo = [];
changed to an object instead of an array
var jo = {};
I also added the if(isNaN(object[key]) inside the inner loop in order to make sure that these didn't show as NaN as I continued adding them together.
$(document).ready(function () {
$("body").click(function () {
var rows = $("tbody tr");
var jo = {};
console.log(rows);
for (var i = 0; i < rows.length; i++) {
for (var j = 1; j <= rows.length; j++) {
var pnt1 = $(rows[i]).find(".pnt").html();
var stations1 = $(rows[i]).find(".station").html();
var pntR1 = $(rows[i]).find(".res").html();
if (pnt1 == $(rows[j]).find(".pnt").html()) {
pntR1 = parseInt(pntR1);
pntR2 = parseInt($(rows[j]).find(".res").html());
if(isNaN(jo[pnt1])){
jo[pnt1] = 0;
}
jo[pnt1] += pntR1;
break;
}
}
}
console.log(jo);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="pntsRes">
<thead>
<tr>
<th>Участники</th>
<th>Баллы</th>
</tr>
</thead>
<tbody>
<tr>
<td class="pnt">aa</td>
<td class="station">AES</td>
<td class="res">1</td>
</tr>
<tr>
<td class="pnt">dd</td>
<td class="station">AES</td>
<td class="res">2</td>
</tr>
<tr>
<td class="pnt">aa</td>
<td class="station">Science</td>
<td class="res">3</td>
</tr>
<tr>
<td class="pnt">dd</td>
<td class="station">Science</td>
<td class="res">4</td>
</tr>
<tr>
<td class="pnt">bb</td>
<td class="station">Аэродром</td>
<td class="res">5</td>
</tr>
<tr>
<td class="pnt">ee</td>
<td class="station">aeroport</td>
<td class="res">6</td>
</tr>
</tbody>
</table>
My table is in format
<table id="mytable">
<thead>
<tr>
<th>name</th>
<th>place</th>
</tr>
</thead>
<tbody>
<tr>
<td>adfas</td>
<td>asdfasf</td>
</tr>
</tbody>
</table>
I found the following code online. But it doesn't work if i use "thead" and "tbody" tags
function write_to_excel() {
str = "";
var mytable = document.getElementsByTagName("table")[0];
var rowCount = mytable.rows.length;
var colCount = mytable.getElementsByTagName("tr")[0].getElementsByTagName("td").length;
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
ExcelSheet.Application.Visible = true;
for (var i = 0; i < rowCount; i++) {
for (var j = 0; j < colCount; j++) {
str = mytable.getElementsByTagName("tr")[i].getElementsByTagName("td")[j].innerHTML;
ExcelSheet.ActiveSheet.Cells(i + 1, j + 1).Value = str;
}
}
Check https://github.com/linways/table-to-excel.
Its a wrapper for exceljs/exceljs to export html tables to xlsx.
TableToExcel.convert(document.getElementById("simpleTable1"));
<script src="https://cdn.jsdelivr.net/gh/linways/table-to-excel#v1.0.4/dist/tableToExcel.js"></script>
<table id="simpleTable1" data-cols-width="70,15,10">
<tbody>
<tr>
<td class="header" colspan="5" data-f-sz="25" data-f-color="FFFFAA00" data-a-h="center" data-a-v="middle" data-f-underline="true">
Sample Excel
</td>
</tr>
<tr>
<td colspan="5" data-f-italic="true" data-a-h="center" data-f-name="Arial" data-a-v="top">
Italic and horizontal center in Arial
</td>
</tr>
<tr>
<th data-a-text-rotation="90">Col 1 (number)</th>
<th data-a-text-rotation="vertical">Col 2</th>
<th data-a-wrap="true">Wrapped Text</th>
<th data-a-text-rotation="-45">Col 4 (date)</th>
<th data-a-text-rotation="-90">Col 5</th>
</tr>
<tr>
<td rowspan="1" data-t="n">1</td>
<td rowspan="1" data-b-b-s="thick" data-b-l-s="thick" data-b-r-s="thick">
ABC1
</td>
<td rowspan="1" data-f-strike="true">Striked Text</td>
<td data-t="d">05-20-2018</td>
<td data-t="n" data-num-fmt="$ 0.00">2210.00</td>
</tr>
<tr>
<td rowspan="2" data-t="n">2</td>
<td rowspan="2" data-fill-color="FFFF0000" data-f-color="FFFFFFFF">
ABC 2
</td>
<td rowspan="2" data-a-indent="3">Merged cell</td>
<td data-t="d">05-21-2018</td>
<td data-t="n" data-b-a-s="dashed" data-num-fmt="$ 0.00">230.00</td>
</tr>
<tr>
<td data-t="d">05-22-2018</td>
<td data-t="n" data-num-fmt="$ 0.00">2493.00</td>
</tr>
<tr>
<td colspan="4" align="right" data-f-bold="true" data-a-h="right" data-hyperlink="https://google.com">
<b>Hyperlink</b>
</td>
<td colspan="1" align="right" data-t="n" data-f-bold="true" data-num-fmt="$ 0.00">
<b>4933.00</b>
</td>
</tr>
<tr>
<td colspan="4" align="right" data-f-bold="true" data-a-rtl="true">
مرحبا
</td>
<td colspan="1" align="right" data-t="n" data-f-bold="true" data-num-fmt="$ 0.00">
<b>2009.00</b>
</td>
</tr>
<tr>
<td data-b-a-s="dashed" data-b-a-c="FFFF0000">All borders</td>
</tr>
<tr>
<td data-t="b">true</td>
<td data-t="b">false</td>
<td data-t="b">1</td>
<td data-t="b">0</td>
<td data-error="#VALUE!">Value Error</td>
</tr>
<tr>
<td data-b-t-s="thick" data-b-l-s="thick" data-b-b-s="thick" data-b-r-s="thick" data-b-t-c="FF00FF00" data-b-l-c="FF00FF00" data-b-b-c="FF00FF00" data-b-r-c="FF00FF00">
All borders separately
</td>
</tr>
<tr data-exclude="true">
<td>Excluded row</td>
<td>Something</td>
</tr>
<tr>
<td>Included Cell</td>
<td data-exclude="true">Excluded Cell</td>
<td>Included Cell</td>
</tr>
</tbody>
</table>
This creates valid xlsx on the client side. Also supports some basic styling. Check https://codepen.io/rohithb/pen/YdjVbb for a working example.
Only works in Mozilla, Chrome and Safari..
$(function() {
$('button').click(function() {
var url = 'data:application/vnd.ms-excel,' + encodeURIComponent($('#tableWrap').html())
location.href = url
return false
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
</script>
<button>click me</button>
<div id="tableWrap">
<table>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
</div>
The reason the solution you found on the internet is no working is because of the line that starts var colCount. The variable mytable only has two elements being <thead> and <tbody>. The var colCount line is looking for all the elements within mytable that are <tr>. The best thing you can do is give an id to your <thead> and <tbody> and then grab all the values based on that. Say you had <thead id='headers'> :
function write_headers_to_excel()
{
str="";
var myTableHead = document.getElementById('headers');
var rowCount = myTableHead.rows.length;
var colCount = myTableHead.getElementsByTagName("tr")[0].getElementsByTagName("th").length;
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
ExcelSheet.Application.Visible = true;
for(var i=0; i<rowCount; i++)
{
for(var j=0; j<colCount; j++)
{
str= myTableHead.getElementsByTagName("tr")[i].getElementsByTagName("th")[j].innerHTML;
ExcelSheet.ActiveSheet.Cells(i+1,j+1).Value = str;
}
}
}
and then do the same thing for the <tbody> tag.
EDIT: I would also highly recommend using jQuery. It would shorten this up to:
function write_to_excel()
{
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
ExcelSheet.Application.Visible = true;
$('th, td').each(function(i){
ExcelSheet.ActiveSheet.Cells(i+1,i+1).Value = this.innerHTML;
});
}
Now, of course, this is going to give you some formatting issues but you can work out how you want it formatted in Excel.
EDIT: To answer your question about how to do this for n number of tables, the jQuery will do this already. To do it in raw Javascript, grab all the tables and then alter the function to be able to pass in the table as a parameter. For instance:
var tables = document.getElementsByTagName('table');
for(var i = 0; i < tables.length; i++)
{
write_headers_to_excel(tables[i]);
write_bodies_to_excel(tables[i]);
}
Then change the function write_headers_to_excel() to function write_headers_to_excel(table). Then change var myTableHead = document.getElementById('headers'); to var myTableHead = table.getElementsByTagName('thead')[0];. Same with your write_bodies_to_excel() or however you want to set that up.
Excel Export Script works on IE7+ , Firefox and Chrome
===========================================================
function fnExcelReport()
{
var tab_text="<table border='2px'><tr bgcolor='#87AFC6'>";
var textRange; var j=0;
tab = document.getElementById('headerTable'); // id of table
for(j = 0 ; j < tab.rows.length ; j++)
{
tab_text=tab_text+tab.rows[j].innerHTML+"</tr>";
//tab_text=tab_text+"</tr>";
}
tab_text=tab_text+"</table>";
tab_text= tab_text.replace(/<A[^>]*>|<\/A>/g, "");//remove if u want links in your table
tab_text= tab_text.replace(/<img[^>]*>/gi,""); // remove if u want images in your table
tab_text= tab_text.replace(/<input[^>]*>|<\/input>/gi, ""); // reomves input params
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) // If Internet Explorer
{
txtArea1.document.open("txt/html","replace");
txtArea1.document.write(tab_text);
txtArea1.document.close();
txtArea1.focus();
sa=txtArea1.document.execCommand("SaveAs",true,"Say Thanks to Sumit.xls");
}
else //other browser not tested on IE 11
sa = window.open('data:application/vnd.ms-excel,' + encodeURIComponent(tab_text));
return (sa);
}
Just Create a blank iframe
enter code here
<iframe id="txtArea1" style="display:none"></iframe>
Call this function on
<button id="btnExport" onclick="fnExcelReport();"> EXPORT
</button>
This might be a better answer copied from this question.
<script type="text/javascript">
function generate_excel(tableid) {
var table= document.getElementById(tableid);
var html = table.outerHTML;
window.open('data:application/vnd.ms-excel;base64,' + base64_encode(html));
}
function base64_encode (data) {
// http://kevin.vanzonneveld.net
// + original by: Tyler Akins (http://rumkin.com)
// + improved by: Bayron Guevara
// + improved by: Thunder.m
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfixed by: Pellentesque Malesuada
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: Rafal Kukawski (http://kukawski.pl)
// * example 1: base64_encode('Kevin van Zonneveld');
// * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
// mozilla has this native
// - but breaks in 2.0.0.12!
//if (typeof this.window['btoa'] == 'function') {
// return btoa(data);
//}
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
ac = 0,
enc = "",
tmp_arr = [];
if (!data) {
return data;
}
do { // pack three octets into four hexets
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);
bits = o1 << 16 | o2 << 8 | o3;
h1 = bits >> 18 & 0x3f;
h2 = bits >> 12 & 0x3f;
h3 = bits >> 6 & 0x3f;
h4 = bits & 0x3f;
// use hexets to index into b64, and append result to encoded string
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);
enc = tmp_arr.join('');
var r = data.length % 3;
return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
}
</script>
function XLExport() {
try {
var i;
var j;
var mycell;
var tableID = "tblInnerHTML";
var objXL = new ActiveXObject("Excel.Application");
var objWB = objXL.Workbooks.Add();
var objWS = objWB.ActiveSheet;
for (i = 0; i < document.getElementById('<%= tblAuditReport.ClientID %>').rows.length; i++) {
for (j = 0; j < document.getElementById('<%= tblAuditReport.ClientID %>').rows(i).cells.length; j++) {
mycell = document.getElementById('<%= tblAuditReport.ClientID %>').rows(i).cells(j);
objWS.Cells(i + 1, j + 1).Value = mycell.innerText;
}
}
//objWS.Range("A1", "L1").Font.Bold = true;
objWS.Range("A1", "Z1").EntireColumn.AutoFit();
//objWS.Range("C1", "C1").ColumnWidth = 50;
objXL.Visible = true;
}
catch (err) {
}
}
Check this out... I just got this working and it seems exactly what you are trying to do as well.
2 functions. One to select the table and copy it to the clipboard, and the second writes it to excel en masse. Just call write_to_excel() and put in your table id (or modify it to take it as an argument).
function selectElementContents(el) {
var body = document.body, range, sel;
if (document.createRange && window.getSelection) {
range = document.createRange();
sel = window.getSelection();
sel.removeAllRanges();
try {
range.selectNodeContents(el);
sel.addRange(range);
} catch (e) {
range.selectNode(el);
sel.addRange(range);
}
} else if (body.createTextRange) {
range = body.createTextRange();
range.moveToElementText(el);
range.select();
}
range.execCommand("Copy");
}
function write_to_excel()
{
var tableID = "AllItems";
selectElementContents( document.getElementById(tableID) );
var excel = new ActiveXObject("Excel.Application");
// excel.Application.Visible = true;
var wb=excel.WorkBooks.Add();
var ws=wb.Sheets("Sheet1");
ws.Cells(1,1).Select;
ws.Paste;
ws.DrawingObjects.Delete;
ws.Range("A1").Select
excel.Application.Visible = true;
}
Heavily influenced from: Select a complete table with Javascript (to be copied to clipboard)
I think you can also think of alternative architectures. Sometimes something can be done in another way much more easier. If the producer of HTML file is you, then you can write an HTTP handler to create an Excel document on the server (which is much more easier than in JavaScript) and send a file to the client. If you receive that HTML file from somewhere (like an HTML version of a report), then you still can use a server side language like C# or PHP to create the Excel file still very easily. I mean, you may have other ways too. :)
I would suggest using a different approach. Add a button on the webpage that will copy the content of the table to the clipboard, with TAB chars between columns and newlines between rows. This way the "paste" function in Excel should work correctly and your web application will also work with many browsers and on many operating systems (linux, mac, mobile) and users will be able to use the data also with other spreadsheets or word processing programs.
The only tricky part is to copy to the clipboard because many browsers are security obsessed on this. A solution is to prepare the data already selected in a textarea, and show it to the user in a modal dialog box where you tell the user to copy the text (some will need to type Ctrl-C, others Command-c, others will use a "long touch" or a popup menu).
It would be nicer to have a standard copy-to-clipboard function that possibly requests a user confirmation... but this is not the case, unfortunately.
I try this with jquery;
use this and have fun :D
jQuery.printInExcel = function (DivID)
{
var ExcelApp = new ActiveXObject("Excel.Application");
ExcelApp.Workbooks.Add;
ExcelApp.visible = true;
var str = "";
var tblcount = 0;
var trcount = 0;
$("#" + DivID + " table").each(function ()
{ $(this).find("tr").each(function ()
{ var tdcount = 0; $(this).find("td").each(function ()
{ str = str + $(this).text(); ExcelApp.Cells(trcount + 1, tdcount + 1).Value = str;
str = ""; tdcount++
});
trcount++
}); tblcount++
});
};
use this in your class and call it with $.printInExcel(your var);
function exportExcelFromTable(){
let table = document.getElementById('tableId');
console.log(table);
TableToExcel.convert(table, {
name: `export.xlsx`,
sheet: {
name: 'Exported_Data' // sheetName
}
});
}
exportTable() {
if (this.arrayname.length >= 1) { //here your array name which are display in table
$('#exportable tr td').css('text-align', 'center'); //table formating
const downloadLink = document.createElement('a');
const table = document.getElementById('exportable');
const tableHTML = table.outerHTML.replace(/ /g, '%20');
var html = table.outerHTML;
var url = 'data:application/vnd.ms-excel,' + escape(html); // Set your html table into url
downloadLink.href = 'data:' + url + ' ';
downloadLink.download = 'tablename.xls'
downloadLink.click();
} else {
alert('table is empty')
}}
` //table tab should be like this <table class="table class" id="exportable" border="1" style="border-collapse: collapse;">
//button <button class="btn btn-xs btn-primary "(click)="exportTable();">
<i class="fa fa-file-excel-o m-right-5"></i>
<span>Export Excel</span>
</button>