How can I display names by using loop with setTimeout() function - javascript

I was trying to display members' names in the div element after 3 seconds by using for loop with setTimeout() function. But I'm getting an undefined values of the names array. And even the value of var i displaying 4. I don't know why. Can anyone explain to me why and how to fix that.?
Thanks in advance!
JS Code:
function members() {
var arr = ["Joseph","John","Kumar","Shiva"];
var i;
for(i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log("Member = " + i + ". " + arr[i]);
document.getElementById("Names").innerHTML = "Member = " + i + ". " + arr[i];
}, 3000);
}
}
members();
<div id="Names"></div>

First, Because var is a function scope ( not block scope like for loop ), when the setTimeout execute after 3 sec, the loop will be ended and the value of i will be equal to the arr.length, and arr[arr.lenght] will equal to undefined.
To solve this issue, one solution is using let instead of var.
Second, If you want to add the members to HTML, you need to use += to concatenate with the previous string not = which will re-initialize the innerHTML
const names = document.getElementById("Names");
function members() {
var arr = ["Joseph","John","Kumar","Shiva"];
for(let i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log("Member = " + i + ". " + arr[i]);
document.getElementById("Names").innerHTML += `Member = ${(i + 1)}. ${arr[i]}<br />`;
}, 3000);
}
}
members();
<div id="Names"></div>

I think better solution for you here is to execute a function after 3 seconds, rather then putting the timeout inside for loop.
That was what was causing your issue, as the var is a function scoped variable. So by putting timeout inside of for loop, the last element would be undefined since your script would read the last element as arr.length, which is 4, and you don't have arr[4], hence it is undefined.
Also, your innerHTML was not written properly, if you want to print multiple values, you need to use innerHTML += instead of innerHTML = because innerHTML = will always print the last value from your loop, because it erases the innerHTML of your element in each new iteration.
I modified your code snippet below.
https://codepen.io/Juka99/pen/VwxpXwL

Related

Code is getting stuck somewhere in a succession of for-loops and I'm not sure why

EDIT - I changed the code to correctly declare variables below but nothing seems to have changed
I've written code using a for-loop that has to satisfy a number of criteria before executing what's within it. The problem is that, somewhere along the way, the code is getting stuck inside one of the loops, causing the computer to crash.
I've tried breaking the loop but this doesn't seem to help.
function compareKeypoints(varifiedKeypoints) {
outer_loop: for (i = 0; i < varifiedKeypoints.length; i++) {
let initialKeypoint = varifiedKeypoints[i];
for (j = 0; j < varifiedKeypoints.length; j++) {
let comparisonKeypoint = varifiedKeypoints[j];
if (initialKeypoint.part != comparisonKeypoint.part) {
if (Math.abs(comparisonKeypoint.position.x - initialKeypoint.position.x) <= 20
&& Math.abs(comparisonKeypoint.position.y - initialKeypoint.position.y) <= 20) {
if (keypointsCompatible(initialKeypoint.part, comparisonKeypoint.part)) {
console.log("Activating part: " + initialKeypoint.part);
console.log("Activated part: " + comparisonKeypoint.part);
let keypointPair = {
point_1: initialKeypoint.part,
point_2: comparisonKeypoint.part
}
console.log("Pushing parts!");
activeParts.push(keypointPair);
console.log("breaking loop!");
break outer_loop;
console.log("Loop NOT broken!!");
}
}
}
}
}
if (activeParts.length > 0) {
console.log(activeParts);
}
}
function keypointsCompatible(keypoint_1, keypoint_2) {
var outcome = true;
if (activeParts.length > 0) {
compatibility_loop: for (i = 0; i < activeParts.length; i++) {
if (Object.values(activeParts[i]).includes(keypoint_1) && Object.values(activeParts[i]).includes(keypoint_2)) {
console.log(keypoint_1 + " and " + keypoint_2 + " are not compatible because they already exist as " + activeParts[i].point_1 + " and " + activeParts[i].point_2 + " respectively");
outcome = false;
break compatibility_loop;
console.log("Compatibility NOT broken!!");
}
}
}
console.log("Compatibility outcome is " + outcome);
return outcome;
}
The code is suppose to take two values in the same array and compare them. If a number of conditions are met, including if they're a certain distance apart from one another, they will be pushed into a secondary array. If the values already appear in the secondary array, which the keypointCompatible function is suppose to determine, the loop should either continue looking for other candidates or stop before being called again. For some reason, however, the code is getting stuck within the keypointCompatible function when it detects that the values have already appeared in the secondary array and the console will repeatedly print "Compatibility is false" until the browser crashes.
Working Solution
Use let or const instead of var or nothing. Your issue may be related to closures and variables reused between loops. Make sure you use let or const in your loops too. for (let i=0).
When you use let or const, the runtime will create a new instance every time the block or loop iterates. However, using var will reuse the internal allocation.
So what happens with the standard var is the multiple closures or loops each use the same instance of the variable.
Unless you want the var behavior, always use let or const.
Another Solution
Put a newline after the label compatibility_loop
Still Another Solution
The first function is pushing into activeParts. The second function is looping activeParts. This can go on forever, or longer than expected. Pushing into the array could possibly make the loop limit never reached.
Put a log on the length of activeParts in the second function to see if it is growing out of control.
Your code should be OK if varifiedKeypoints.length has reasonable value. And all internal variables are declared properly!
You have two loops (this inner can start at j=i+1 to save time and multiple calculations) with few conditions inside.
function compareKeypoints(varifiedKeypoints) {
outer_loop: for (let i = 0; i < varifiedKeypoints.length; i++) {
let initialKeypoint = varifiedKeypoints[i];
for (let j = i+1; j < varifiedKeypoints.length; j++) {
let comparisonKeypoint = varifiedKeypoints[j];

Pass variable into document.getElementById() - Javascript

I am running a function that populates several paragraph tags on a webpage with the days of the week. The function takes an array of days which is populated based on the current day (i.e. if today is Thursday, get the next 7 days in order).
My problem is that for some reason, I am unable to populate these tags. I have checked to make sure that the array is getting populated and the list is being iterated through. While both of these are true, none of the Inner HTML of the tags are being changed.
HTML:
<p class="mb-1" id="forecastDay1" runat="server">Day</p>
<p class="mb-1" id="forecastDay2" runat="server">Day</p>
JavaScript Function:
function populatePage(arry) {
var i;
for (i = 0; i < arry.length - 1; i++) {
var id = "forecastDay" + i.toString();
document.getElementById(id).innerHTML = arry[i].toString();
}
}
I have also tried it this way:
document.getElementById("forecastDay" + i.toString()).innerHTML = arry[i].toString();
You do not need toString in JavaScript.
Also, arrays start at 0, while your elements start at 1. You have to compensate that difference.
function populatePage(arry) {
var i;
for (i = 0; i < arry.length; i++) {
var id = "forecastDay" + (i + 1);
document.getElementById(id).innerHTML = arry[i];
}
}
// Test it
populatePage(["Day 1", "Day 2"]);
<p class="mb-1" id="forecastDay1" runat="server">Day</p>
<p class="mb-1" id="forecastDay2" runat="server">Day</p>
There are a few things wrong with your code:
The first value of i is 0. Since there is not element #forecastDay0, getElementById will return null. Trying to access innerHTML of null will throw an error, thus breaking the for loop and every thing after it. You should check your console when something doesn't work, it's a great way to debug.
The check for the for loop should be i < arry.length not i < arry.length - 1.
You don't need any of the toString calls.
That being said, here is how it should be:
function populatePage(arry) {
var i;
for (i = 0; i < arry.length; i++) {
var id = "forecastDay" + (i + 1); // i + 1 instead of just i. The casting to strings is done automatically
document.getElementById(id).textContent = arry[i]; // use textContent as there isn't really any HTML
}
}

javascript for loop executes only once

for(var i=0; i < imageFiles.length; i++)
{
console.log('index value : ' + i)
let item = imageFiles[i]
let file = item.getAsFile()
let oValue = await self.getOrientation(file)
console.log('orientation value : ' + oValue)
}
The for loop above is only executing once, could someone provide a solution that will make the loop iterate over all the files in the array ?
From within the parentheses, you defined the variable "i" with a value of 0. As a result, i++ will return 1 and also save it to "i". You said it's only executing once for some reason, clearly this is part of the issue.
Check to make sure any code related to this is written as intended.

How can I loop over element ids in an array and assign them to variables?

I'm trying to refactor my window.onload function so as to avoid redundancy. I'd like to loop over the elements I'm assigning to global variables, using their ids. Initially, I was able to assign onclick functions with a loop, but now I'm not able to reproduce this in a fiddle. But the main issue is simply trying to do this (see fiddle):
var gragh, gorgh;
var ids = ["gragh", "gorgh"];
for (var i = 0; i < ids.length; i++) {
ids[i] = document.getElementById(ids[i]);
// TypeError: document.getElementById(ids[i]).onclick = doStuff;
}
//console.log(gragh); undefined
This is supposed to assign the variables gragh and gorgh to p elements which have the same ids. Within the loop, ids[i] seems to refer to the p elements. After the loop, however, these variables are undefined. This also doesn't work when looping through an array with these variables not surrounded by quotes. I've even tried using eval(), with mixed results. So my question is, how can I get this to work? And also, why doesn't this work? If ids = [gragh, gorgh] (without the quotes), what do these variables within the array refer to?
Don't reassign it in your loop, try using a new array to populate. Think of it as a reference - you're modifying it while looping.
var gragh, gorgh;
var ids = ["gragh", "gorgh"];
var newSet = [];
for (var i = 0; i < ids.length; i++) {
newSet[i] = document.getElementById(ids[i]);
}
Loop will finish it's looping much before this onclick executes.So at that time the value of i will be the upper limit of the loop.
A work around of this a closure
var gragh;
var ids = ["gragh", "gorgh"];
for (var i=0; i<ids.length; i++) {
(function(i){ // creating closure
console.log(i)
document.getElementById(ids[i]).onclick = doStuff
})(i) // passing value of i
}
document.getElementById("gragh").innerHTML = "ids[0]: " + ids[0] + ", ids[1]: " + ids[1]
function doStuff() {
document.getElementById("gorgh").innerHTML = "ids[0]: " + ids[0] + ",ids[1]: " + ids[1] + ", var gragh: " + gragh;
}
gragh is undefined since you haveonly declared it but never initialized it
JSFIDDLE

JQuery for loop stuck at last index [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
jQuery Looping and Attaching Click Events
(4 answers)
Closed 9 years ago.
I have function process_row that appends tags to html, and those tags are chained to a function upon clicked. (in this case, simply alert(i), its position in the result array).
But however, upon being clicked, the newly generated alerts the length of the entire result array. I have tried many, many changes to try and make it work, but it doesn't.
Strange thou, fab_div.attr("id", result_data[0]); works fine !! In Chrome inspect element the id tags are displayed as they are, but the click function points everything to the last element in the array.
for example, if I do, fab_div.click(function () { alert(result_data[0]) });, I get the name of the LAST element in the array, doesn't matter which element was clicked.
can anyone please explain to me... WHY??
I think it may have something to do with $("<div>") where JQuery thinks it's the same div that it's assigning to. Is there any way around this? The 's are generated dynamically and I would not want to let PHP do the echoing. Plus the content may be updated realtime.
Example dataset :
Smith_Jones#Smith#Jones#janet_Moore#Janet#Moore#Andrew_Wilson#Andrew#Wilson
After many, many changes, still not working:
function process_row(data){
result_array = data.split("#");
if(result_array.length > 0){
result_data =result_array[0].split("#");
for(i = 0; i < result_array.length; i++){
result_data =result_array[i].split("#");
var fab_text = result_data[1] + " " + result_data[2]
var fab_div = $("<div>");
fab_div.addClass('scroll_tap');
fab_div.attr("id", result_data[0]);
fab_div.append(fab_text)
// fab_div.click(function () { alert(i) });
// ^ not working, try appending list of id's to id_list
id_list.push(result_data[0])
$('#ls_admin').append(fab_div)
}
for(j = 0; j < id_list.length; j++){
$('#' + id_list[j]).click(function () { alert(j) })
}
}
}
Original Attempt:
function process_row(data){
result_array = data.split("#");
if(result_array.length > 0){
result_data =result_array[0].split("#");
for(i = 0; i < result_array.length; i++){
result_data =result_array[i].split("#");
var fab_text = result_data[1] + " " + result_data[2]
var fab_div = $("<div>").append(fab_text).click(function () { alert(i) });
fab_div.addClass('scroll_tap');
fab_div.attr("id", result_data[0]);
$('#ls_admin').append(fab_div)
}
}
}
If you must use an alert, then you can encapsulate the click handler in a self executing function and pass the index to it. Like,
(function (index) {
fab_div.click(function () {
alert(index);
});
})(i);
Although, this is not a clean way to do it. Otherwise, if you are looking to just manipulate the div element is any way, then adding any method directly will also work. Like,
fab_div.click(function () {
alert($(this).attr('id'));
});
You can refer a jsFiddle here
Wonky Solution, but it worked! Haha! Big thanks to Kevin B.
function process_row(data){
result_array = data.split("#");
if(result_array.length > 0){
result_data =result_array[0].split("#");
for(i = 0; i < result_array.length; i++){
result_data =result_array[i].split("#");
var fab_text = result_data[1] + " " + result_data[2]
var fab_div = $("<div>").append(fab_text);
fab_div.addClass('scroll_tap');
fab_div.attr("id", result_data[0]);
$('#ls_admin').append(fab_div)
}
$("#ls_admin").children(this).each(function( index ) {
$(this).append($(this).click(function () { alert($(this).text()) }));
});
}
}

Categories

Resources