This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript infamous Loop problem?
For some reason I get "6" inside my function here for every div element:
for(var i = 1; i <= 5; i++){
$('<div class="e-' + i + '"></div>').appendTo(something).click(function(){
alert(i); // <-- it's 6. wtf??
});
}
instead of 1, 2, 3, etc.
The class on the other hand it appears to be correctly set..
What am I doing wrong?
Your for loop is being executed at page load time. The alert only fires when there's a click event which is happening after the for loop has finished. Hence the value of i is now 6.
1) Page loads, for loop does its stuff...
2) Sometime later a click event is fired. the value of i at this time is 6 because the forloop has already completed.
The problem is that you need to create a closure to capture the value of i at the time you bind the click function.
Try this:
for(var i = 1; i <= 5; i++)
{
$('<div class="e-' + i + '"></div>')
.appendTo(something)
.click(function(value)
{
return function() { alert(value) };
}(i));
}
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Javascript infamous Loop issue? [duplicate]
(5 answers)
Closed 2 years ago.
I am adding some JS to an HTML, and I have a fragment of code similar to this:
<script>
function ButtonAction(index){
alert("My index is: "+index);
if(window_big){
// Use index to do something
}
else{
// Use index to do something else
}
}
function WindowResize(){
if(window.innerWidth > 1200){
window_big = true;
}
else{
window_big = false;
}
}
var window_big;
if(window.innerWidth > 1200){
window_big = true;
}
else{
window_big = false;
}
buttons = document.getElementsByClassName('MyButtons')
var i;
for (i = 0; i < buttons.length; i++) {
alert(i);
buttons[i].addEventListener("click",function(){ButtonAction(i);},false);
}
window.onresize = WindowResize;
</script>
The idea can be summarized like this:
There is a series of buttons in the page, stored in buttons[].
If the window is bigger than a certain size, those buttons should do one action, and if not, do another one.
To do said actions, I need the button[x].id. In fact, the initial intention was to set the listener to:
buttons[i].addEventListener("click",function(){ButtonAction(i);},false);
The problem is that I cannot retrieve the id, because the argument passed in the event listener seems to be always the last value i was set to.
May I ask for some help, please?
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 4 years ago.
I have a question which might sound silly. In the code below there are 2 console.log(i) statements. I want to know why does the second console.log(i) statement returns value of 2 and not 1 as the former on the first iteration (i.e. 1st statement i=n, 2nd: i=n+1). Shouldn't both be equal to 1 until the end of the loop?
function toggleWrapper(){
var el1 = document.querySelectorAll('[class="tCell entryDesc"]');
for (var i = 1; i < el1.length; i++) {
console.log(i);
el1[i].addEventListener('click', function(ev){
console.log(i);
var el2=document.querySelectorAll('[class="additionalInfoContainer"]');
if (el2[i-2].clientHeight) {
el2[i-2].style.maxHeight = 0;
}
else{
el2[i-2].style.maxHeight = el2[i-2].scrollHeight +"px";
}
},
false);
}
}
The problem is that the variable i, within each of your addEventListener() functions, is bound to the same variable outside of the function. simply change your for loop to :
for (let i = 1; i < el1.length; i++)
In the loop with let based index, each iteration through the loop will have a new value of i where each value is scoped inside the loop, so your code would work fine.
i think is something in your code because if you try to make a for loop with two "console.log()" it doesn't do that
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
This is a bit of a mystery for me. I have two functions:
1)
var revisionNumber;
var $list = $('<ul>');
TFS_Wit_WebApi.getClient().getWorkItem(284)
.then(function(query) {
revisionNumber = query.rev;
});
2)
for (i = 0; i < revisionNumber; i++) {
TFS_Wit_WebApi.getClient().getRevision(284, 6)
.then(function(query) {
$list.append($('<li>').text("story board" + revisionNumber));
});
}
The reivisonNumber value is supposed to be 15. When in for loop I put instead of the variable a number 15, the second function works just fine as well as for loop and it actually displays this number 15.
If I remove for loop, it also works and displays the value of revisionNumber variable from the first function.
However, when I put revisionNumber in my for loop, the second function does not work at all.
Why is it not going inside the second function with the above for loop?
The for loop is probably being executed before the getWorkItem().then() callback is being executed. You will need to wait for that callback to run before running the for loop, either by moving it into the callback function, or putting it in it's own function and calling that function in the callback.
For example:
var revisionNumber;
var $list = $('<ul>');
TFS_Wit_WebApi.getClient().getWorkItem(284).then(function (query) {
revisionNumber = query.rev;
for (i = 0; i < revisionNumber; i++) {
TFS_Wit_WebApi.getClient().getRevision(284, 6).then(function (query) {
$list.append($('<li>').text("story board" + revisionNumber));
});
}
});
This question already has answers here:
jQuery Looping and Attaching Click Events
(4 answers)
Closed 7 years ago.
I'm trying to loop through 12 classes, named .video-link0 through video-link11, where each one gets the treatment:
$('.video-link[n]').click(function() {
$('.video-link[n]').addClass('show');
});
Essentially, I want the following behavior:
When .video-link1 is clicked, addClass('show') to video-link1
When .video-link2 is clicked, addClass('show') to video-link2
and so on, as if I had 12 functions that looked like this:
$('.video-link1').click(function() {
$('.video-link1').addClass('show');
});
$('.video-link2').click(function() {
$('.video-link2').addClass('show');
});
... and so on
I want to write a single loop that replaces the need to write this out as 12 separate cases.
The following does not yield the result I'm looking for:
var elems = 12;
for(var i = 0; i < elems; i++){
$('.video-link' + i).click(function() {
$('.video-link' + i).addClass('show');
});
};
** UPDATE **
This is not a duplicate question, or else the above question referenced does not address my requirement. I am not trying to move up and down the DOM with next. Rather, I want to write a single loop that iterates through 12 classes numbered 0-11 using i to enumerate the cases.
** UPDATE **
This works for me, and is using a suggestion by Lloyd Banks (I needed the i enumerator PLUS the this keyword):
for (var i = 0; i < 12; i++) {
$('.video-link'+i).click(function() {
$(this).addClass('show');
});
}
You can use starts with ^= selector and reference each with $(this)
$("[class^='video-link']").click(function() {
$(this).addClass('show');
});
You can use $(this) to reference the current (targeted) element inside of a event callback:
$('.video-link').click(function() {
$(this).addClass('show');
});
You can use
function(numberOfElements){
for(var i = 1; i <= numberOfElements; i++){
$('.video-link' + i).on('click', function(){
$(this).addClass('show');
});
}
}
You should also be using the .on binding event instead of .click. If you are generating your element after initial page load and use .click, the event handler wouldn't be registered.
This question already has answers here:
How do I pass the value (not the reference) of a JS variable to a function? [duplicate]
(6 answers)
Closed 8 years ago.
I have a script that needs a function to be run multiple times per object, but the number of objects is set in a variable by the user.
It would work like this
dothis(1);
dothis(2);
dothis(3);
However this doesn't work
for (var i = 0; i < howMany; i++)
{
setInterval(
function()
{
dothis(i);
},
(Math.floor(Math.random() * 10) + 1)
);
}
You need to snapshot the value of i in a local scope otherwise it gets dynamically 'regenerated' at execution time, which means the value would then always be howMany, since the CPU lock, created by the main function, prevents your setInterval/setTimeout functions to execute before the loop is ended.
for (var i = 0; i < howMany; i++)
{
setInterval(
function(j)
{
return function() { dothis(j); };
}(i),
(Math.floor(Math.random() * 10) + 1)
);
}
See How do JavaScript closures work? for further reference.