Split Table into Individual Tables with One Row with Javascript - javascript

I would like to split this entire table into three sub tables using Javascript. Each table should retain it's header information.
I cannot adjust the id's or classes as they are generated by a web application, so I need to make do with what is available.
I've been trying to crack this with Jfiddle for quite awhile and am getting frustrated. I'm pretty new to Javascript, but can't image this would require a lot of code. If anyone knows how to split this apart by row size as well (i.e. Split Table up, but selectively), that would be appreciated as well.
I'm limited to Javascript and Jquery 1.7.
<div id="serviceArray">
<table border="1" class="array vertical-array">
<thead>
<tr>
<th>#</th>
<th>Savings</th>
<th>Expenses</th>
<th>Savings</th>
<th>Expenses</th>
<th>Savings</th>
<th>Expenses</th>
</tr>
</thead>
<tbody>
<tr>
<td>Sum</td>
<td>$180</td>
<td>$500</td>
<td>$300</td>
<td>$700</td>
<td>$600</td>
<td>$1000</td>
</tr>
<tr>
<td>Home</td>
<td>$100</td>
<td>$200</td>
<td>$200</td>
<td>$300</td>
<td>$400</td>
<td>$500</td>
</tr>
<tr>
<td>Work</td>
<td>$80</td>
<td>$300</td>
<td>$100</td>
<td>$400</td>
<td>$200</td>
<td>$500</td>
</tr>
</tbody>
</table>
</div>

Did you mean like this?
var tables = $('#serviceArray table tbody tr').map(function () { //For each row
var $els = $(this).closest('tbody') //go to its parent tbody
.siblings('thead').add( //fetch thead
$(this) //and add itself (tr)
.wrap($('<tbody/>')) //wrapping itself in tbody
.closest('tbody')); //get itself with its tbody wrapper
return $els.clone() //clone the above created steps , i.e thead and tbody with one tr
.wrapAll($('<table/>', { //wrap them all to a new table with
'border': '1', //attributes.
'class': 'array vertical-array'
})
).closest('table'); //get the new table
}).get();
$('#serviceArray table').remove();
$('body').append(tables); //append all to the table.
Demo
Or just simply clone the table and remove all other trs from tbody except this one and add it to DOM (Much Shorter Solution).
var tables = $('#serviceArray table tbody tr').map(function (idx) {
var $table = $(this).closest('table').clone().find('tbody tr:not(:eq(' + idx + '))').remove().end();
return $table;
}).get();
Demo
Each of the methods used has documentation available in web and you can use this to work out something yourself to what you need.

You can use simple Javascript for table creation and it will generate rows according to your returned response from api.
var tableHeader = this.responseJsonData.Table_Headers;
var tableData = this.responseJsonData.Table_Data;
let table = document.querySelector("table");
function generateTableHead(table, data) {
//alert("In Table Head");
let thead = table.createTHead();
let row = thead.insertRow();
for (let key of data) {
let th = document.createElement("th");
let text = document.createTextNode(key);
th.appendChild(text);
row.appendChild(th);
}
}
function generateTable(table, data) {
// alert("In Generate Head");
for (let element of data) {
let row = table.insertRow();
for (key in element) {
let cell = row.insertCell();
let text = document.createTextNode(element[key]);
cell.appendChild(text);
}
}
}

Related

javascript im trying to append button to the end of each row in my table

so im trying to add a buttons to the end of each row since the table is dynamic I have to use javascript to append it but everytime I try it doesn't work if it does it will just put a button at the end of the last row of the table. Heres an image of what I get linked below
enter image description here
<!--TABLE HEADER SECTION-->
<div class="div0">
<table class="tableHeader">
<thead>
<tr>
<th>Store</th>
<th>Product</th>
<th>Profile</th>
<th>Proxies</th>
<th>Status</th>
<th>ACTION</th>
</tr>
</thead>
</table>
</div>
<!--TABLE SECTION-->
<div class="div1">
<table id = "botTasksTable" class="table table-dark table-sm table-bordered">
<tbody>
<tr>
<td>another name</td>
<td>mockdata</td>
<td>mockdata</td>
<td>mockdata</td>
<td>mockdata</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
const tableBody = document.querySelector("#botTasksTable > tbody");
//function to load table into tbody from jsonfile bottable which would be the users given tasks
function loadBotTasksTable() {
const request = new XMLHttpRequest();
request.open("get", "data/botTable.json"); //grabs the data from the json file its in the data file/ and named bottable.json
request.onload = () => {
const json = JSON.parse(request.responseText); //attempts to parse the data it gets
populateTable(json);
};
request.send(); //sends out the request for thr function
}
var btn = document.createElement("BUTTON");
var btn = document.createElement("BUTTON"); // Create a <button> element
btn.innerHTML = "CLICK ME"; // Insert text
function populateTable(json) {
//this while loop clears out existing table data!
//we want to add this back but adding a value to first child even if its a mock value.
while (tableBody.firstChild) { //so basically checking if the table has <tr> <td></td> </tr> so a row and column
tableBody.removeChild(tableBody.firstChild)
}
//now we populate table
json.forEach((row) => { //loops through each row [ SUPREME, Nike SB Dunks, profile1, proxy22, In Progress ]
const tr = document.createElement("tr"); //create the new row
row.forEach((cell) => { //loops through each individual column of the row EX : SUPREME
const td = document.createElement("td");
td.textContent = cell // passes whatever data the json file had in the cell into the text content of the row
tr.appendChild(td);
});
//for each cell in the row get the index and append
tableBody.appendChild(tr); //appends the row into the table body row by row as i runs through the for loop
});
loopTable();
}
//loop through table and add button to the table
function loopTable() {
var table = document.getElementById('botTasksTable');
for (var i = 0, row; row = table.rows[i]; i++) {
//iterate through rows
//rows would be accessed using the "row" variable assigned in the for loop
row.appendChild(btn);
console.log(i);
}
};
You need to create a new button for each row, and put it inside a <td>. You can use cloneNode() to make a copy of an element.
//loop through table and add button to the table
function loopTable() {
var table = document.getElementById('botTasksTable');
for (var i = 0, row; row = table.rows[i]; i++) {
let td = document.createElement('td');
td.appendChild(btn.cloneNode());
row.appendChild(td);
console.log(i);
}
};

How to filter dynamic HTML table using javascript

I am appending rows to the table whenever a event is occurring.But when I am trying to filter the table, I am only able to filter the static data in the table. How can I also filter the appended rows. Please help me with this.
//Filter rows
var $rows = $('#table tr');
$('#search').keyup(function() {
var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
reg = RegExp(val, 'i'),
text;
$rows.show().filter(function() {
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
}).hide();
});
The variable rows is initialised with the rows in the DOM at the moment you tell jQuery to get those elements. No matter how many rows you add or remove, the rows variable will always have the same set of element. The quickest solution is to move your variable declaration inside the keyup handler like this:
$('#search').keyup(function() {
var $rows = $('#table tr');
var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
reg = RegExp(val, 'i'),
text;
$rows.show().filter(function() {
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
}).hide();
});
Another solution would the use getElementsByTagName, this returns a live HTMLCollection. In other words, changes in the DOM are reflected in your variable as they occur. The snippet below will log the number of rows in the table without re-querying the DOM.
const
tableTwo = document.getElementById('table2'),
// Get a live HTMLCollection with the rows in table 2.
tableTwoRows = tableTwo.getElementsByTagName('tr');
// Log the number of rows in table 2.
console.log(`Number of rows in table 2 before insert: ${tableTwoRows.length}`);
const
cell = document.createElement('td'),
row = document.createElement('tr'),
body = tableTwo.querySelector('tbody');
// Create a third row to add to the table.
cell.textContent = 'table 2, row 3';
row.appendChild(cell);
body.appendChild(row);
// Log the number of rows in table 2, this should report a number than the last
// log eventhough we didn't update the content of the tableTwoRows variable manually.
console.log(`Number of rows in table 2 after insert: ${tableTwoRows.length}`);
<table id="table1">
<tbody>
<tr>
<td>table 1, row 1</td>
</tr>
</tbody>
</table>
<table id="table2">
<tbody>
<tr>
<td>table 2, row 1</td>
</tr>
<tr>
<td>table 2, row 2</td>
</tr>
</tbody>
</table>

Append tr's to tbody of existing table inside div container?

I have existing table where I would like to add/append tbody element. Here is example of my HTML table:
<div id="myDiv">
<table class="myTable">
<thead>
<tr>
<th>ID</th>
<th>Last</th>
<th>First</th>
<th>DOB</th>
<th>Nickname</th>
</tr>
</thead>
</table>
</div>
Here is my JavaScript/JQuery code:
var divID = $('#myDiv table.myTable');
var tbl = "<tbody>";
for(var i=0; i < numRecs; i++){
var jsRec = obj.DATA[i];
tbl += "<tr id='lookup_"+i+"'>";
tbl += "<td>"+decodeURIComponent(jsRec.ID)+"</td>";
tbl += "<td>"+decodeURIComponent(jsRec.LAST)+"</td>";
tbl += "<td>"+decodeURIComponent(jsRec.FIRST)+"</td>";
tbl += "<td>"+decodeURIComponent(jsRec.DOB)+"</td>";
tbl += "<td>"+decodeURIComponent(jsRec.NICKNAME)+"</td></tr>";
}
tbl += "</tbody>";
divID.append(tbl);
$.alert(divID,'Main Menu',1000,600); //JQuery dialog box that takes html variable, title, width and height
I'm getting blank content in my dialog box with this code. If anyone can help or see where is my code breaking please let me know. Thank you.
It looks like you're not closing the <tr> in your loop, making a series open-ended table-rows. jQuery validates HTML before appending into the DOM so it's likely silently failing when trying to append.
I would separate the creation of elements in small chunks a shown in the following example. That way it would be easier to separate were things are going south. You´ll probably only need to replace sampleData[i]["id"] with decodeURIComponent(jsRec.ID), etc. I only created the sampleData Array for the examples sake. It might also be possible to execute decodeURIComponent() for each of the properties of your object inside a loop.
(function($) {
$(document).ready(function() {
var sampleData = [{
id: 1,
last: "lst",
first: "first",
DOB: "IDK",
nickname: "nick"
}];
var divID = $('#myDiv table.myTable tbody');
var current, row, cell;
for (var i = 0; i < sampleData.length; i++) {
row = $("<tr></tr>"); //Create a row
cell = $("<td></td>").html(sampleData[i]["id"]); //Create a cell
row.append(cell); //Append The cell
cell = $("<td></td>").html(sampleData[i]["last"]);
row.append(cell);
cell = $("<td></td>").html(sampleData[i]["first"]);
row.append(cell);
cell = $("<td></td>").html(sampleData[i]["DOB"]);
row.append(cell);
cell = $("<td></td>").html(sampleData[i]["nickname"]);
row.append(cell);
divID.append(row); //Add Row to the Table
}
});
})(jQuery);
td,
th,
tr {
border: 1px solid gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="myDiv">
<table class="myTable">
<thead>
<tr>
<th>ID</th>
<th>Last</th>
<th>First</th>
<th>DOB</th>
<th>Nickname</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
At the end you might have trouble with $.alert(divID,'Main Menu',1000,600); but all you might need is to add a toString() or something like that.

Delete all rows in an HTML table

How can I delete all rows of an HTML table except the <th>'s using Javascript, and without looping through all the rows in the table? I have a very huge table and I don't want to freeze the UI while I'm looping through the rows to delete them
this will remove all the rows:
$("#table_of_items tr").remove();
Keep the <th> row in a <thead> and the other rows in a <tbody> then replace the <tbody> with a new, empty one.
i.e.
var new_tbody = document.createElement('tbody');
populate_with_new_rows(new_tbody);
old_tbody.parentNode.replaceChild(new_tbody, old_tbody)
Very crude, but this also works:
var Table = document.getElementById("mytable");
Table.innerHTML = "";
Points to note, on the Watch out for common mistakes:
If your start index is 0 (or some index from begin), then, the correct code is:
var tableHeaderRowCount = 1;
var table = document.getElementById('WRITE_YOUR_HTML_TABLE_NAME_HERE');
var rowCount = table.rows.length;
for (var i = tableHeaderRowCount; i < rowCount; i++) {
table.deleteRow(tableHeaderRowCount);
}
NOTES
1. the argument for deleteRow is fixed
this is required since as we delete a row, the number of rows decrease.
i.e; by the time i reaches (rows.length - 1), or even before that row is already deleted, so you will have some error/exception (or a silent one).
2. the rowCount is taken before the for loop starts
since as we delete the "table.rows.length" will keep on changing, so again you have some issue, that only odd or even rows only gets deleted.
Hope that helps.
This is an old question, however I recently had a similar issue.
I wrote this code to solve it:
var elmtTable = document.getElementById('TABLE_ID_HERE');
var tableRows = elmtTable.getElementsByTagName('tr');
var rowCount = tableRows.length;
for (var x=rowCount-1; x>0; x--) {
elmtTable.removeChild(tableRows[x]);
}
That will remove all rows, except the first.
Cheers!
If you can declare an ID for tbody you can simply run this function:
var node = document.getElementById("tablebody");
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
Assuming you have just one table so you can reference it with just the type.
If you don't want to delete the headers:
$("tbody").children().remove()
otherwise:
$("table").children().remove()
hope it helps!
I needed to delete all rows except the first and solution posted by #strat but that resulted in uncaught exception (referencing Node in context where it does not exist). The following worked for me.
var myTable = document.getElementById("myTable");
var rowCount = myTable.rows.length;
for (var x=rowCount-1; x>0; x--) {
myTable.deleteRow(x);
}
the give below code works great.
It removes all rows except header row. So this code really t
$("#Your_Table tr>td").remove();
this would work iteration deletetion in HTML table in native
document.querySelectorAll("table tbody tr").forEach(function(e){e.remove()})
Assing some id to tbody tag. i.e. . After this, the following line should retain the table header/footer and remove all the rows.
document.getElementById("yourID").innerHTML="";
And, if you want the entire table (header/rows/footer) to wipe out, then set the id at table level i.e.
How about this:
When the page first loads, do this:
var myTable = document.getElementById("myTable");
myTable.oldHTML=myTable.innerHTML;
Then when you want to clear the table:
myTable.innerHTML=myTable.oldHTML;
The result will be your header row(s) if that's all you started with, the performance is dramatically faster than looping.
If you do not want to remove th and just want to remove the rows inside, this is working perfectly.
var tb = document.getElementById('tableId');
while(tb.rows.length > 1) {
tb.deleteRow(1);
}
Pure javascript, no loops and preserving headers:
function restartTable(){
const tbody = document.getElementById("tblDetail").getElementsByTagName('tbody')[0];
tbody.innerHTML = "";
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<table id="tblDetail" class="table table-bordered table-hover table-ligth table-sm table-striped">
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 2</th>
<th>Header 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>
a
</td>
<td>
b
</td>
<td>
c
</td>
<td>
d
</td>
</tr>
<tr>
<td>
1
</td>
<td>
2
</td>
<td>
3
</td>
<td>
4
</td>
<tr>
<td>
e
</td>
<td>
f
</td>
<td>
g
</td>
<td>
h
</td>
</tr>
</tr>
</tbody>
</table>
<button type="button" onclick="restartTable()">restart table</button>
If you have far fewer <th> rows than non-<th> rows, you could collect all the <th> rows into a string, remove the entire table, and then write <table>thstring</table> where the table used to be.
EDIT: Where, obviously, "thstring" is the html for all of the rows of <th>s.
This works in IE without even having to declare a var for the table and will delete all rows:
for(var i = 0; i < resultsTable.rows.length;)
{
resultsTable.deleteRow(i);
}
this is a simple code I just wrote to solve this, without removing the header row (first one).
var Tbl = document.getElementById('tblId');
while(Tbl.childNodes.length>2){Tbl.removeChild(Tbl.lastChild);}
Hope it works for you!!.
Assign an id or a class for your tbody.
document.querySelector("#tbodyId").remove();
document.querySelectorAll(".tbodyClass").remove();
You can name your id or class how you want, not necessarily #tbodyId or .tbodyClass.
#lkan's answer worked for me, however to leave the first row, change
from
for (var x=rowCount-1; x>0; x--)
to
for (var x=rowCount-1; x>1; x--)
Full code:
var myTable = document.getElementById("myTable");
var rowCount = myTable.rows.length;
for (var x=rowCount-1; x>1; x--) {
myTable.deleteRow(x);
}
This will remove all of the rows except the <th>:
document.querySelectorAll("td").forEach(function (data) {
data.parentNode.remove();
});
Same thing I faced. So I come up with the solution by which you don't have to Unset the heading of table only remove the data..
<script>
var tablebody =document.getElementById('myTableBody');
tablebody.innerHTML = "";
</script>
<table>
<thead>
</thead>
<tbody id='myTableBody'>
</tbody>
</table>
Try this out will work properly...
Assuming the <table> element is accessible (e.g. by id), you can select the table body child node and then remove each child until no more remain. If you have structured your HTML table properly, namely with table headers in the <thead> element, this will only remove the table rows.
We use lastElementChild to preserve all non-element (namely #text nodes and ) children of the parent (but not their descendants). See this SO answer for a more general example, as well as an analysis of various methods to remove all of an element's children.
const tableEl = document.getElementById('my-table');
const tableBodyEl = tableEl.querySelector('tbody');
// or, directly get the <tbody> element if its id is known
// const tableBodyEl = document.getElementById('table-rows');
while (tableBodyEl.lastElementChild) {
tableBodyEl.removeChild(tableBodyEl.lastElementChild);
}
<table id="my-table">
<thead>
<tr>
<th>Name</th>
<th>Color</th>
</tr>
</thead>
<tbody id="table-rows">
<tr>
<td>Apple</td>
<td>Red</td>
</tr>
<!-- comment child preserved -->
text child preserved
<tr>
<td>Banana</td>
<td>Yellow</td>
</tr>
<tr>
<td>Plum</td>
<td>Purple</td>
</tr>
</tbody>
</table>
Just Clear the table body.
$("#tblbody").html("");
const table = document.querySelector('table');
table.innerHTML === ' ' ? null : table.innerHTML = ' ';
The above code worked fine for me. It checks to see if the table contains any data and then clears everything including the header.

Can't set innerHTML on tbody in IE

I have a table like this:
<table>
<thead>
<tr>
<th colspan="1">a</th>
<th colspan="3">b</th>
</tr>
</thead>
<tbody id="replaceMe">
<tr>
<td>data 1</td>
<td>data 2</td>
<td>data 3</td>
<td>data 4</td>
</tr>
</tbody>
</table>
and a method returns me the following after an ajax request:
<tr>
<td>data 1 new</td>
<td>data 2 new</td>
<td>data 3 new</td>
<td>data 4 new</td>
</tr>
I want to change the innerHTML like
document.getElementById('replaceMe').innerHTML = data.responseText;
However, it seems that IE can't set innerHTML on <tbody>. Can anyone help me with a simple workaround for this issue?
That is true, innerHTML on tbody elements is readOnly in IE
The property is read/write for all
objects except the following, for
which it is read-only: COL, COLGROUP,
FRAMESET, HEAD, HTML, STYLE, TABLE,
TBODY, TFOOT, THEAD, TITLE, TR.
source: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
You can do something like this to work around it:
function setTBodyInnerHTML(tbody, html) {
var temp = tbody.ownerDocument.createElement('div');
temp.innerHTML = '<table>' + html + '</table>';
tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody);
}
Basically it creates a temporary node into which you inject a full table. Then it replaces the tbody with the tbody from the injected table. If it proves to be slow, you could make it faster by caching temp instead of creating it each time.
Create a temp node to store a table in, then copy them to the tbody
var tempNode = document.createElement('div');
tempNode.innerHTML = "<table>" + responseText+ "</table>";
var tempTable = tempNode.firstChild;
var tbody = // get a reference to the tbody
for (var i=0, tr; tr = tempTable.rows[i]; i++) {
tbody.appendChild(tr);
}
Both the answers above seem a bit unclear. Plus, the created div is never removed, so calling those functions repeatedly eats memory. Try this:
// this function must come before calling it to properly set “temp”
function MSIEsetTBodyInnerHTML(tbody, html) { //fix MS Internet Exploder’s lameness
var temp = MSIEsetTBodyInnerHTML.temp;
temp.innerHTML = '<table><tbody>' + html + '</tbody></table>';
tbody.parentNode.replaceChild(temp.firstChild.firstChild, tbody); }
MSIEsetTBodyInnerHTML.temp = document.createElement('div');
if (navigator && navigator.userAgent.match( /MSIE/i ))
MSIEsetTBodyInnerHTML(tbody, html);
else //by specs, you can not use “innerHTML” until after the page is fully loaded
tbody.innerHTML=html;
Even with this code, though, MSIE does not seem to properly re-size the table cells in my application, but I'm filling an empty tbody tag with variable generated content, while the thead cells' colspan values are set to a fixed value: the maximum number of cells that may be in the generated tbody. While the table tbody is 50 cells wide, only two columns show. Perhaps if the table was originally filled, and the cells were replaced with the same internal structure, this method would work. Google's Chrome does an excellent job of rebuilding the table, while Opera's desktop browser can resize to more columns just fine, but if you remove columns, the remaining column widths remain as narrow as they were; however with Opera, by hiding the table (display=none) then re-showing it (display=table), the generated table tbody cells then size properly. I've given up with Firefox. It's the MSIE-6 of 2012 - a nightmare to develop for which must have additional markup added just to make HTML-CSS layouts work because it does not conform to standards that even MSIE now does. So I haven't tested the tbody.innerHTML workings in Firefox.
This can be fixed by creating a shim/polyfill for .innerHTML. This could get you (you, dear reader) started:
if (/(msie|trident)/i.test(navigator.userAgent)) {
var innerhtml_get = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerHTML").get
var innerhtml_set = Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerHTML").set
Object.defineProperty(HTMLElement.prototype, "innerHTML", {
get: function () {return innerhtml_get.call (this)},
set: function(new_html) {
var childNodes = this.childNodes
for (var curlen = childNodes.length, i = curlen; i > 0; i--) {
this.removeChild (childNodes[0])
}
innerhtml_set.call (this, new_html)
}
})
}
var mydiv = document.createElement ('div')
mydiv.innerHTML = "test"
document.body.appendChild (mydiv)
document.body.innerHTML = ""
console.log (mydiv.innerHTML)
http://jsfiddle.net/DLLbc/9/
<table id="table">
<thead>
<tr>
<th colspan="1">a</th>
<th colspan="3">b</th>
</tr>
</thead>
<tbody id="replaceMe">
<tr>
<td>data 1</td>
<td>data 2</td>
<td>data 3</td>
<td>data 4</td>
</tr>
</tbody>
</table>
<button type="button" onclick="replaceTbody()">replaceTbody</button>
<script>
function $(id){
return document.getElementById(id);
}
function replaceTbody(){
var table = $('table');
table.removeChild($('replaceMe'));
var tbody = document.createElement("tbody");
tbody.setAttribute("id","replaceMe");
table.appendChild(tbody);
var tr = document.createElement('tr');
for(var i=1;i<5;i++){
var td = document.createElement('td');
td.innerHTML = 'newData' + i;
tr.appendChild(td);
}
tbody.appendChild(tr);
}
</script>

Categories