I have this really bizarre issue where I have a forloop that is supposed to replace all divs with the class of "original" to text inputs with a class of "new". When I run the loop, it only replaces every-other div with an input, but if I run the loop to just replace the class of the div and not change the tag to input, it does every single div, and doesn't only do every-other.
Here is my loop code, and a link to the live version: live version here
function divChange() {
var divs = document.getElementsByTagName("div");
for (var i=0; i<divs.length; i++) {
if (divs[i].className == 'original') {
var textInput = document.createElement('input');
textInput.className = 'new';
textInput.type = 'text';
textInput.value = divs[i].innerHTML;
var parent = divs[i].parentNode;
parent.replaceChild(textInput, divs[i]);
}
}
}
I have this really bizarre issue where I have a forloop that is supposed to replace all divs with the class of "original" to text inputs with a class of "new". When I run the loop, it only replaces every-other div with an input, but if I run the loop to just replace the class of the div and not change the tag to input, it does every single div, and doesn't only do every-other.
Here is my loop code, and a link to the live version: live version here
function divChange() {
var divs = document.getElementsByTagName("div");
for (var i=0; i<divs.length; i++) {
if (divs[i].className == 'original') {
var textInput = document.createElement('input');
textInput.className = 'new';
textInput.type = 'text';
textInput.value = divs[i].innerHTML;
var parent = divs[i].parentNode;
parent.replaceChild(textInput, divs[i]);
}
}
}
Share
Improve this question
asked Nov 4, 2012 at 16:37
CJT3CJT3
2,9287 gold badges34 silver badges45 bronze badges
13
-
Iterate in reverse instead of forward. When you remove the
div
, it also gets removed from thedivs
collection, so you end up skipping indices. – I Hate Lazy Commented Nov 4, 2012 at 16:38 - ah, so have var i = divs.length; i>0; i--? – CJT3 Commented Nov 4, 2012 at 16:40
-
1
Yes, almost.
var i = divs.length - 1; i > -1; i--
– I Hate Lazy Commented Nov 4, 2012 at 16:41 - ah, brilliant. too bad you didn't post this as an answer. lol – CJT3 Commented Nov 4, 2012 at 16:42
-
@user1689607 Or
for ( var i = divs.length - 1; i--; )...
– David G Commented Nov 4, 2012 at 16:42
4 Answers
Reset to default 6Because the divs
collection is updated when one of its div
elements is removed from the DOM, you end up skipping over divs because your i
isn't updated with the reindexing of the collection.
A mon solution is to iterate in reverse instead.
function divChange() {
var divs = document.getElementsByTagName("div");
for (var i=divs.length - 1; i > -1; i--) {
if (divs[i].className == 'original') {
var textInput = document.createElement('input');
textInput.className = 'new';
textInput.type = 'text';
textInput.value = divs[i].innerHTML;
divs[i].parentNode.replaceChild(textInput, divs[i]);
}
}
}
Another solution you could use is to copy the live HTMLCollection to an inert array, and use your original logic:
function divChange() {
var divs = document.getElementsByTagName("div");
divs = Array.prototype.slice.call( divs ); //convert to array
for (var i = 0; i < divs.length; i++) {
if (divs[i].className == 'original') {
var textInput = document.createElement('input');
textInput.className = 'new';
textInput.type = 'text';
textInput.value = divs[i].innerHTML;
var parent = divs[i].parentNode;
parent.replaceChild(textInput, divs[i]);
}
}
}
divChange();
http://jsfiddle/2UCZa/1/
Yet another solution is to create an Array from an array-like object, and iterate over this. For example:
var divs = document.getElementsByTagName("div");
Array.from(divs).forEach(function(el) {
if (el.className == 'original') {
var textInput = document.createElement('input');
textInput.className = 'new';
textInput.type = 'text';
textInput.value = el.innerHTML;
var parent = el.parentNode;
parent.replaceChild(textInput, el);
}
});
I like this one the best, as it produces the least amount of code, and is very clear!
I don't know why, but this one seemed to work in the end:
ModalBody.insertAdjacentHTML('afterbegin', loader.outerHTML);
my loader is basically just a new div, but inside of the div there is this loading symbol, which appears when the content is loaded.
var loader = document.createElement('div');
loader.classList.add('loader');
loader.classList.add('is-loading');
loader.classList.add('mt-5');
So with just this line
ModalBody.insertAdjacentHTML('afterbegin', loader);
...while the content was loaded a got [object HTMLDivElement] shown shortly, after 3 sec more or less the right content appeared. As soon as I added this ".outerHTML" things got right. I am still a super beginner. So, maybe someone could also explaine why this worked?