0

Struggling on a for loop.. I cant seem to make it work..Trying to add a for loop to the (".circle" + (i+1)) Selector but not hiding and fading in one circle(i). Is this possible or some similar approach?

Any help would be appreciate it!

<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<ul class="menu">
  <li class="first"><a href="#btn1">btn1</a></li>
  <li class="second"><a href="#btn2">btn2</a></li>
  <li class="third"><a href="#btn3">btn3</a></li>
  <li class="forth"><a href="#btn4">btn4</a></li>
</ul>

<div class="circle1 circle">1</div>
<div class="circle1 circle">2</div>
<div class="circle1 circle">3</div>
<div class="circle4 circle">4</div>

<script>
for(i=0;i<$(".menu li").length;i++){
    $(".menu li").eq(i).on('click',function(){
      $(".circle").hide();
      $('.circle'+(i+1)).stop().fadeIn('300');
      return false;
    });
  }
</script>
</body>
</html>
1
  • Short answer: closures. i is always equal to it's value at the end of the loop in your click handler. Commented Feb 19, 2014 at 16:54

2 Answers 2

4

Your problem is with the way variables are scoped. i will always have the value that it had at the end of the loop in your click handler. You can fix it like this:

for(i=0;i<$(".menu li").length;i++){
    (function(j) {
        $(".menu li").eq(j).on('click',function(){
            $(".circle").hide();
            $('.circle'+(j+1)).stop().fadeIn('300');
            return false;
        });
    })(i);
}

What the above does is create a closure by using an Immediately Invoked Function Expression (IIFE) that creates a new scope and copies the value of i during the loop.

It would also be assign $(".menu li").length to a variable before the loop so that jQuery isn't recreating the collection every time it loops.

To understand what's going on, compare this:

for(i=0;i<5;i++){
    setTimeout(function() {
        console.log(i);
    },100);
}

// outputs: 5 5 5 5 5

To this:

for(i=0;i<5;i++){
    (function(i) {
        setTimeout(function() {
            console.log(i);
        },100);
    })(i);
}

// outputs: 0 1 2 3 4

http://jsfiddle.net/PLsUN/

Sign up to request clarification or add additional context in comments.

Comments

0

Matt Burland's answer is correct and very thorough. This is merely an alternate suggestion to avoid using the for loop (if you prefer):

// Use the jQuery's already-available `.each` method
$(".menu li").each(function(index, list_element){

    (function(list_index){ // as per Matt's answer
        list_element.on('click',function(){
            $(".circle").hide();
            $('.circle'+(list_index+1)).stop().fadeIn('300');
            return false;
        }
    })(index);

});

The effect is the same, and there is no performance difference (so far as I know); I find it slightly cleaner.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.