2

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!

nouklea
  • 69
  • 7
  • 3
    Well, `getElementsByTagNames` is a syntax error, it should be [`getElementsByTagName`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName) ? – adeneo Dec 17 '15 at 16:22
  • Yes indeed. I had it correctly written in my code, but copied it too quickly here. Thanks. I made the correction in the original post. – nouklea Dec 21 '15 at 14:13

3 Answers3

3

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/

dfsq
  • 191,768
  • 25
  • 236
  • 258
0

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

Community
  • 1
  • 1
wotanii
  • 2,470
  • 20
  • 38
  • He's removing the row from the DOM and not from the array(-like) `rows`. The array is updated because it's a live collection which is updated with each `row.parentNode.remove(row)` – Andreas Dec 17 '15 at 16:33
0

try to replace this line

var rows = table.getElementsByTagNames("tr");

by

var rows = table.find("tr");
j08691
  • 204,283
  • 31
  • 260
  • 272