I have a Javascript Array that holds the contents of a page. In order to draw all the objects in the right places when the page loads I loop over the array and pull out the elements. This worked very well until I allowed the objects to have children within them.
The current array structure is
0-> {elements=[] frame={I keep the frame attributes here with key value pairs}}, 1-> {elements=[] frame={}}
However, I just started adding sub-elements to the elements array in each object. So now I have to loop through/draw each element, check to see if there are any children and if so then I have to draw them too.
The problem I'm having is that after I loop through the first 0 object and it's children the for loop stops running. Is it because I'm calling the same function multiple times? I've done that before so I don't think that's what is happening.
this.run_loop = function (spawn, dom) {
console.log(spawn)
alert(spawn.length)
for (i = 0; i < spawn.length; i++) {
console.log(spawn[i])
//alert("i one")
var newdom = dom + "_" + i;
this.synthesize_elements(spawn[i], dom, newdom)
if (spawn[i].hasOwnProperty('elements')) {
//alert("FOUND")
var newarray = spawn[i]['elements'];
if (newarray.length > 0) {
this.run_loop(newarray, newdom)
}
}
}
}
This is a little old but I encountered a similar issue and found my way here, but I figured it out and thought I'd post the solution if anyone else came across this. The issue in my case (and it looks like in your case as well though I can't be sure) was in the declaration of the for loop:
for (i = 0; i < spawn.length; i++)
You're not declaring that i is a new var. so if anything inside the
this.run_loop(newarray, newdom)
function also manipulates a counter variable called i that isn't declared a new var, it will also change the one in your outer scope, and kick you out of the loop if it goes over the length of spawn
just always declare:
for (var i; i< spawn.length; i++)
in your loops or make sure your counters are unique.
Related
I wrote a function to change the class of elements to change their properties. For some reason, only some of the elements have changed. It took me a few hours to find a solution, but it seems odd to me. Perhaps you can explain this to me.
This isn’t working:
function replace(){
var elements = document.getElementsByClassName('classOne');
for (var i = 0; i < elements.length; i++) {
elements[i].className = 'classTwo';
}
}
See the JSFiddle: only every second item is affected; only every second red element changes color to blue.
So I changed the final expression of the for loop to not increment i anymore:
function replace(){
var elements = document.getElementsByClassName('classOne');
for (var i = 0; i < elements.length; i) { // Here’s the difference
elements[i].className = 'classTwo';
}
}
This works well! It seems as though push is called and no increment is needed. Is this normal? It is different from the examples I’ve seen.
What's going on is an odd side effect. When you reassign className for each element of elements, the element gets removed from the array! (Actually, as # user2428118 points out, elements is an array-like object, not an array. See this thread for the difference.) This is because it no longer has the classOne class name. When your loop exits (in the second case), the elements array will be empty.
You could write your loop as:
while (elements.length) {
elements[0].className = 'classTwo'; // removes elements[0] from elements!
}
In your first case, by incrementing i, you are skipping half of the (original) elements that have class classOne.
Excellent question, by the way. Well-researched and clear.
getElementsByClassName returns a NodeList. A NodeList collection is a live collection, which means that the modification of the document affects the collection. more
Or revert the loop, beginning by length-1 and step down to 0
My file works just fine in the first round of loop when i try to rerun the function again. It shows the previous value of the previous loop when i try to use the value to match and after which it shows the correct value. If i run the function again and again, it keeps holding on to the value of the previous generated random value.
for (var i=0; i<9; i++)
{
var ranD = Math.floor(Math.random()*33);
if (mathStar.indexOf(ranD)== -1) {
mathStar.push(ranD);
item[i].innerHTML = mathStar[i];
}
else {
i--;
}
itemVal[i].value = mathStar[i];
}
Substitute using const and let for var within for loop to avoid creating global variables and --i could have unexpected results within the code where i++ is also used in the foor loop.
Is this the first occurrence of "mathStar"?
If this is the first place you're using mathStar, it means it gets created globally and that usually leads to confusion. In this case, take a look at this.
Looking at just this, it seems that you are not resetting your "mathStar" value. This way, any time you run this loop for the nth time, the values you have added to "mathStar" using mathStar.push(...) also occur in the list of values.
Fellow Stackers.
I am attempting the following:
for(let i = 0; i <= promoObj.length - 1; i++) {
document.getElementById(promoObj[i]["note"]).addEventListener("click",
function(){
onPromoView(promoObj[i])
}, false);
}
promoObj is an object containing several arrays. i is the index of each array. When I run the loop shown above, onPromoView(promoObj[i] is rendered literally as onPromoView(promoObj[i] and not with the looped index number such as onPromoView(promoObj[0].
How do I get the event listener to render with the actual index number? I've tried many ways and did much searching but nothing is working. Hopefully, someone here has the answer.
BTW, I prefer the solution in vanilla JS.
Thanks.
Rudy
Why would a for loop terminate early in JavaScript? For some reason my outer for loop terminates after the first repetition. I am new to JavaScript but would expect something like this to work in Java.
function check(){
var elements = document.getElementById('fields').children;
var filteredMolecules = molecules;
console.log(elements.length);
for (i = 0; i < elements.length; i++) {
console.log(elements[i].id)
filterMolecules(filteredMolecules, elements[i].id, 0, 10);
}
}
function filterMolecules(molecules, parameter, lower, upper){
console.log('filtering');
var filteredMolecules = [];
for (i=0;i<molecules.length;i++){
var value = molecules[i].val()[parameter];
filteredMolecules.push(molecules[i]);
}
molecules=filteredMolecules;
}
In check(), I loop through elements which contains 22 items as shown by the first console.log(elements.length). If I remove the method filterMolecules(...) then all 22 IDs are logged. However, with the code as is, only the first id is logged.
I believe the filterMolecules method which should run elements.length number of times is causing the outer for loop to not work. Could someone please explain why this is happening. If relevant, in filterMolecules(...) the data is retrieved from Google Firebase with molecules[i].val()[parameter]. Additionally, both methods use the global variable molecules (line 3 and line 14)
When you don't declare variables in javascript you end up using globals (which can be a difficult to spot source of bugs). So here you are using the same global variable i for both loops. When you start looping thought molecules you are accidentally incrementing the counter loop of your first for. Use different variables or define them with :
for (let i=0;i<molecules.length;i++)
Which will give each loop its own version of i.
In this case, since the declarations are inside individual functions, you could use var too:
for (var i=0;i<molecules.length;i++) {
// etc.
}
i want to perform a loop that writes strings in a div without overloading. I have got a list of names in an global array called names. The array is filled with about 2500 names. Now i want to write the names in a div using ajax. But when i want to loop the names, the script is kinda overloading and stops with an alert of the client. This is my loop:
for(var i = 0; i < names.length; i++){
document.getElementById('div').innerHTML += names[i] + "<br/>";
}
I also tried to interlace the loop in smaller steps like 100 (because i thought like that the loop wouldnt overload). I also tried it with window.setTimeout("function(i)",0); with the param i, that steps 100 each time the function gets called, until i am at the length of the array names.
I know there is an easy way. But i can't find that way..... would be pleased by getting help.
Thanks
You can code it like:
document.getElementById('div').innerHTML = names.join('<br/>');
This will set the inner html in single instruction, solving the load issue.
try it this way:
var content = '';
for(var i = 0, n_length = names.length; i < n_length; i++) {
content += names[i] + "<br/>";
}
document.getElementById('div').innerHTML += content; // if the previous content should remain there
Please note that its faster, to store the abort value of a loop. Otherwise it would read the length-property of your array for each iteration of your loop (2500 x).
Also note that DOM-Manipulation is very verys slow, so its smart to reduce it to the lowest level possible. Better build your content separately and write it to the DOM once for all.