Removing HTMLCollection elements from the DOM
dom, javascript
Solution
The problem is that `paragraphs` is a live list. By removing a `p` element, you are also changing that list. A simple fix is to iterate over the list in reverse order:
for (var i = paragraphs.length - 1; i >= 0; --i) {
paragraphs[i].remove();
}
The alternative solution is to create a static list (non-live list). You can do this by either:
converting the list into an `Array`:
var paragraphs =
Array.prototype.slice.call(document.getElementsByTagName('p'), 0);
using `document.querySelectorAll`:
var paragraphs = document.querySelectorAll('p');
You can then iterate over the list in regular order (using a `for` loop):
for (var i = 0; i < paragraphs.length; ++i) {
paragraphs[i].remove();
}
or (using a `for...of` loop):
for (var paragraph of paragraphs) {
paragraph.remove();
}
Note that `.remove` is a relatively new DOM method, and not supported in every browser. See the MDN documentation for more info.
To illustrate the problem, let’s imagine we have a node list of three elements, `paragraphs = [p0, p1, p2]`. Then this is what happens when you iterate over the list:
i = 0, length = 3, paragraphs[0] == p0 => paragraphs = [p1, p2]
i = 1, length = 2, paragraphs[1] == p2 => paragraphs = [p1]
i = 2, length = 1, END
So in this example, `p1` is not deleted because it is skipped.
Problem
I have a collection of paragraph elements. Some are empty and some contain whitespace only, while others have content: ``` <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p> <p></p> <p> </p> <p> </p> <p> </p> <p> </p> ``` I'm using `getElementsByTagName` to select them: ``` var paragraphs = document.getElementsByTagName('p'); ``` This returns all paragraphs in the document. I want to remove all of them, so I'd like to run ``` for (var i = 0, len = paragraphs.length; i < len; i++) { paragraphs[i].remove(); } ``` but I get `Uncaught TypeError: Cannot read property 'remove' of undefined` errors. I think this is strange, but figure I'll try adding a guard and see what happens: ``` for (var i = 0, len = paragraphs.length; i < len; i++) { paragraphs[i] && paragraphs[i].remove(); } ``` No error, but not all elements are removed. So I run it again, and it removes some of the elements which weren't removed previously. I run it again and finally all of the paragraphs are removed from the document. I'm wondering what obvious detail I'm missing here. Demo of the problem