Since the forEach
array method can now be called on a NodeList
. I was wondering why if you make changes to the content of a childNodes
NodeList while looping with forEach
, forEach
does not detect the changes.
grid.childNodes.forEach(function(tableRow, index, nodeList) {
tableRow.remove();
});
Here, i'm trying to loop through my table(grid) elements children and remove each children(tableRow
) from the table. However, forEach
never completely loop over every element, always leaving out one last tableRow
to be remove
d.I think it has something to do with the childNodes NodeList being live, and the forEach not being able to properly follow it or something.
This is because, at a lower level, the .forEach()
is still keeping a count and using an index of the elements. As you remove some, you are removing them from the beginning of the array/node list, and then the indexer becomes inaccurate because all the element indexes have to get shifted down by one. The element that used to be at index position 5, is now at index position 4, for example.
For something like this, it's always better to use a counting loop and remove elements starting from the last index and working backwards. This will maintain a proper count for the duration of the loop because the element to index mapping won't be modified.
Here's an example:
let grid = document.getElementById("myTable");
document.querySelector("input").addEventListener("click", function(){
for(i = grid.childNodes.length-1; i > -1; i--) {
grid.removeChild(grid.childNodes[i]);
}
});
<table id="myTable">
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
<tr>
<td>Row 3</td>
</tr>
<tr>
<td>Row 4</td>
</tr>
<tr>
<td>Row 5</td>
</tr>
</table>
<input type="button" value="Delete Rows">
Now, you could also make this a little simpler if you were to use the DOM Table API and .deleteRow()
let grid = document.getElementById("myTable");
document.querySelector("input").addEventListener("click", function(){
for(i = grid.rows.length-1; i > -1; i--) {
grid.deleteRow(i);
}
});
<table id="myTable">
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
<tr>
<td>Row 3</td>
</tr>
<tr>
<td>Row 4</td>
</tr>
<tr>
<td>Row 5</td>
</tr>
</table>
<input type="button" value="Delete Rows">
And, of course, you could just wipe out all of the contents of your table by clearing the .innerHTML
.
let grid = document.getElementById("myTable");
document.querySelector("input").addEventListener("click", function(){
grid.innerHTML = "";
});
<table id="myTable">
<tr>
<td>Row 1</td>
</tr>
<tr>
<td>Row 2</td>
</tr>
<tr>
<td>Row 3</td>
</tr>
<tr>
<td>Row 4</td>
</tr>
<tr>
<td>Row 5</td>
</tr>
</table>
<input type="button" value="Delete Rows">