I have an HTML table. The first row contains a checkbox. There is a javascript method associated to the checkbox change. If the checkbox is checked, the code adds a few rows to the table and fills them. If the checkbox is unchecked, the code removes all rows but the first one (the one that contains the checkbox).
The first part of the code works fine : the rows are properly added.
I have an issue with the second part. Here is my code :
if (checkboxValue) {
//Add first row
var tr1 = document.createElement("tr");
var td1_1 = document.createElement("td");
....
tr1.appendChild(td1_1);
var td1_2 = document.createElement("td");
...
tr1.appendChild(td1_2);
table.appendChild(tr1);
//Add second row
var tr2 = document.createElement("tr");
var td2_1 = document.createElement("td");
...
tr2.appendChild(td2_1);
var td2_2 = document.createElement("td");
...
tr2.appendChild(td2_2);
table.appendChild(tr2);
} else {
//Remove all rows but the first
var rows = table.getElementsByTagName("tr");
var nbrRows = rows.length;
if (nbrRows > 1) {
for (var i = 1; i < nbrRows; i++) {
var row = rows[i];
row.parentNode.removeChild(row);
}
}
}
The issue always come from rows[2] being undefined. I have no idea why!
If, instead of using removeChild, I write row.innerHTML = "", I have the visual effect I am looking for (all rows gone), but this is inelegant, since the table now contains several empty rows (their number increasing everytime I check/uncheck the checkbox).
A clue? Thank you very much for your time!
Don't use for-loop to remove DOM elements like this. The problem is that rows is a live collection, meaning that it updates every time you remove elements from DOM. As the result, i counter shifts and eventually you hit "undefined" element spot.
Instead, use while loop. For example, to remove all rows except the first one you could do:
var rows = table.getElementsByTagName("tr");
while (rows.length > 1) {
rows[1].parentNode.removeChild(rows[1]);
}
Also note, that it's getElementsByTagName without s.
UPD. Or iterate backward if you like for-loops better:
var rows = table.getElementsByTagName("tr");
for (var i = rows.length - 1; i > 0; i--) {
rows[i].parentNode.removeChild(rows[i]);
}
Demo: https://jsfiddle.net/9y03co6w/
you remove a row from the array you are iterating over. This is always a bad idea and probably the reason for your error.
solution: start iterating from the end instead of the beginning.
also see for example: example
try to replace this line
var rows = table.getElementsByTagNames("tr");
by
var rows = table.find("tr");
Related
I currently have code that runs through every row of a html table and updates it with a different row.
Here is the code
function sort(index) {
var rows = $table.find('tbody tr');
var a = $table.find('tbody tr');
//Only sort if it has not been sorted yet and the index not the same
if(sortedIndex === index){
for(var i = 0; i < rows.length; i++){
a[i].outerHTML = rows[(rows.length - i)-1].outerHTML;
}
toggleSorted();
}else{
sortedIndex = index;
rows.sort(naturalSort);
for (var i = 0; i < rows.length; i++) {
a[i].outerHTML = rows[i].outerHTML;
}
sortedDown = true;
}
$('#${tableId}').trigger('repaginate');
};
What I am trying to do is to instead of going through every single row in the for loop and setting a[i].outterHTML = rows[i].outterHTML; I would like to just set all of the rows at once. Currently it takes about 1.5 seconds to set them and that is very slow.... Only issue is I cannot seem to find a way to do this. Is this actually possible? (It takes 1.5 seconds on large data sets which is what I am working with).
Since the rows are the same just reordered, you can .append them with the new order:
var $tBody = $table.find('tbody');
var $rows = $tBody.find('tr');
if(sortedIndex === index){
toggleSorted();
$tBody.append($rows.get().reverse());
}
else {
sortedIndex = index;
sortedDown = true;
$tBody.append($rows.get().sort(naturalSort));
}
Here's a fiddle that demonstrates the above: http://jsfiddle.net/k4u45Lnn/1/
Unfortunately the only way to "set all of your rows at once" is to loop through all of your rows and perform an operation on each row. There may be some libraries which have methods and functions that make it look like you're doing the operation on all of your rows at one shot, but ultimately if you want to edit every element in a set you need to iterate through the set and carry out the action on each element, seeing as HTML doesn't really provide any way to logically "link" the attributes of your elements.
when i try to place an unorderd list fetched from the database column, into a dynamically created row of a table(using createElement) it shows the list tags along with the data. but doesn't appear formatted.
here is the code
var table1 = document.getElementById('pc');
for (var x = 1; x < len; x++) {
var vals = result[x];
var row = document.createElement('tr');
row.textContent = vals;
table.appendChild(row);
}
result is from ajax and it has the lists.
By "it shows the list tags along with the data" do you mean it is actually showing the <li> tag instead of actually making a list item?
It might be storing it in your database as < instead of <.
May I know what are the ways to limit the number of columns of a Html table (e.g. 3 columns per row)?
FYI, I'm using row.insertCell() to add cells to a particular row with matching the row id. I wish to limit the cell number to only 3 per row in the table.
"Limit"? There's no natural limit. You'll have to enforce it yourself on your own code.
Check if the row you're inserting into already has 3 cells, and don't add a new one if it does.
Use row.cells collection to check, how many cells a row contains.
var row = document.getElementById('row_id'),
cells = row.cells, max = 3;
if (cells.length < max) {
// Add cell(s) to #row_id
}
There is no such limit in the javascript or html standard. you have to enforce it yourself as a rule during the insertion.
A simple counter does the trick.
var items = ['c00', 'c01', 'c02', 'c10', 'c11', 'c12']; //sample data
var table = document.getElementById("myTable");
var row;
for(var i = 0; i < items.length; i++){
if(i % 3 == 0) { //after every third cell add a new row and change the row variable to point to it
row = table.insertRow(-1);
}
var cell = row.insertCell(-1); //simply insert the row
cell.innerHTML = items[i];
}
there are a number of ways of doing it. it will really depend on how you structure your code.
for(i=0;i<3;i++)
row.insertCell()
I'm having trouble with a function in javascript and can't figure out why. It's really quite straight forward. I'm trying to delete all the rows in a html table. so I wrote:
function delete_gameboard(){
var table = document.getElementById("gameboard");
var rowCount = table.rows.length;
for (var i = 0; i < rowCount; i++) {
table.deleteRow(i);
}
}
Yet, it'll only delete half of them. Can anyone see what's causing this strange behavior?
Because when you delete the first row, the second row will become the first, it's dynamic.
You could do like:
while(table.rows.length > 0) {
table.deleteRow(0);
}
Consider this:
index 0: row #1
index 1: row #2
index 2: row #3
index 3: row #4
index 4: row #5
you delete index #2 (row #3), so the DOM engine adjusts the index keys and you end up with:
index 0: row #1
index 1: row #2
index 2: row #4 <---hey! index #2 is still there
index 3: row #5
You're basically digging a hole in the spot where you're standing, so as you dig deeper, you naturally sink deeper and never see any progress... until you run out of rows to delete in the table.
function delete_gameboard(){
var table = document.getElementById("gameboard");
var rowCount = table.rows.length;
for (var i=rowcount-1; i >=0; i--) {
table.deleteRow(i);
}
}
The index of the row changes when you delete it. Use a reverse loop. This will also be helpful if you are using any condition to delete rows. If you are deleting all rows,use the following
while(table.rows.length) {
table.deleteRow(0);
}
If you delete the first row, the second row becomes the new first row.
I prefer to do this:
while(table.rows[0]) table.deleteRow(0);
You could just go:
document.getElementById("gameboard").innerHTML = "";
The table rows is live, that is if you delete row 0 then the next row becomes row 0, just constantly delete row 0
function delete_gameboard(){
var table = document.getElementById("gameboard");
var rowCount = table.rows.length;
for (var i=0; i < rowCount; i++) {
table.deleteRow(0);
}
}
function delRow()
{
var current = window.event.srcElement;
//here we will delete the line
while ( (current = current.parentElement) && current.tagName !="TR");
current.parentElement.removeChild(current);
}
If you are using JQuery in your code then the easiest way to delete the rows is using the following code:
$('#myTable tbody').html('');
I have a table:
<table>
<tr><td>1</td></tr>
<tr><td>2</td></tr>
<tr><td>3</td></tr>
</table>
An array that tells where every row should come [{index: 2},{index: 1},{index: 0}] (first row is the last from the array, second row is the 1 in array and third row 0 from the array).
Here is my approach.
// create a new temporary tbody outside the DOM (similar to jQuery's detach)
var tbody_tmp = document.createElement('tbody');
// itterate through the array in the order of a new table
for(var i = 0, j = data.length; i < j; i++)
{
// make a copy of current row (otherwise, append child removes the row from the rows array and messes up the index-finder; there got be a better way for this)
var row = rows[data[i].index].cloneNode(true);
tbody_tmp.appendChild(row);
// reset the index to reflect the new table order (optional, outside the sample)
data[i].index = i;
}
// Note that tbody is a jquery object
tbody.parent()[0].replaceChild(tbody_tmp, tbody[0]);
Though, the cloning approach is slow. With 10,000+ records it takes ~1200ms. Furthermore, a jQuery-less approach is preferable.
Posting this in case someone else might find it simple enough for their needs (with less than 1,000 rows).
After hours of restless thinking, I've ended up with the following. If this sample isn't enough, I've written a whole blog post explaining the logic behind it, http://anuary.com/57/sorting-large-tables-with-javascript.
// Will use this to re-attach the tbody object.
var table = tbody.parent();
// Detach the tbody to prevent unnecessary overhead related
// to the browser environment.
var tbody = tbody.detach();
// Convert NodeList into an array.
rows = Array.prototype.slice.call(rows, 0);
var last_row = rows[data[data.length-1].index];
// Knowing the last element in the table, move all the elements behind it
// in the order they appear in the data map
for(var i = 0, j = data.length-1; i < j; i++)
{
tbody[0].insertBefore(rows[data[i].index], last_row);
// Restore the index.
data[i].index = i;
}
// Restore the index.
data[data.length-1].index = data.length-1;
table.append(tbody);