I am trying to replace all text fields on a page with labels.
function replaceInputTextFieldsWithValues() {
var inputFields = document.getElementsByTagName(
What you get back from getElementsByTagName
is an HTMLCollection, which is live. (This is true for the other getElementsByXYZ
methods, but not querySelectorAll
.) That means if you remove the element at index 0
, the HTMLCollection
's length will go down and you'll have a new element at index 0
instead of the one you just removed.
Just work your way through it backward and you'll be fine:
for(var i = inputFields.length - 1; i >= 0; i--) {
// ...
}
Alternately, convert the HTMLCollection
into an array and then loop through the array. (See the live example and code below).
Edit: Or, as Chris Shouts points out in the comments, you can just make use of the changing length
, but it's not quite as simple as Chris' suggestion because you're only removing the elements sometimes. It would look like this:
var inputFields = document.getElementsByTagName("input");
var i = 0;
while (i < inputFields.length) {
if(inputFields[i].getAttribute("type")== "text") {
// Remove it and DON'T increment `index`
}
else {
// Skip this one by incrementing `index`
++index;
}
}
Which of these three approaches to use will depend on the situation. Copying to an array gives you a nice static dataset to work with, and if you make sure to release the reference to the HTMLCollection
, you're giving the browser the opportunity to realize it doesn't have to keep that list up-to-date when things change, which could reduce overhead. But you're copying the references briefly, which increases overhead a bit. :-)
Additional: Here's an example showing this effect, and also showing a fairly efficient (but obscure) way to create an array from a HTMLCollection
:
HTML:
- LI0
- LI1
- LI2
JavaScript:
var lilist, liarray;
// Get the HTMLCollection, which is live
lilist = document.getElementsByTagName('li');
// Create an array of its elements
liarray = Array.prototype.slice.call(lilist, 0);
// Show initial length of both
display("lilist.length = " + lilist.length); // Shows 3
display("liarray.length = " + liarray.length); // Shows 3
// Show what the 0th element of both is (both show "LI0" in the live example)
display("lilist[0].innerHTML = " + lilist[0].innerHTML); // Shows LI0
display("liarray[0].innerHTML = " + liarray[0].innerHTML); // Shows LI0
// Remove the first list item
display("Removing item 0");
lilist[0].parentNode.removeChild(lilist[0]);
// Show the length of both, note that the list's length
// has gone down, but the array's hasn't
display("lilist.length = " + lilist.length); // Shows 2, not 3
display("liarray.length = " + liarray.length); // Still shows 3
// Show what the 0th element of both *now* is
display("lilist[0].innerHTML = " + lilist[0].innerHTML); // Shows LI1 now
display("liarray[0].innerHTML = " + liarray[0].innerHTML); // Still shows LI0
Live copy