1

I am having the code below and javascript's closure together with anonymous functions are giving me a headache.

for (var i = 0, len = sites.length ; i < len ; i++)
{
  $("#thumb"+i).click(function() { $("#shader").show(); $("#thumbInfo"+i).show(); alert("#thumbInfo"+i); });
  $("#thumbInfo"+i+" .xbutton").click(function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); });
}

Due to closure, i is always 5 (the sites array has 5 elements), so all the click handlers refer to the same id.

Any workaround?

1
  • IF you unroll the loop (replace it five times with i hardcoded) does it work? I have a feeling i is not the problem. Commented May 1, 2011 at 4:09

4 Answers 4

6

You could always loop with jQuery's each().

$.each(sites, function(i) {
  $("#thumb"+i).click(function() { $("#shader").show(); $("#thumbInfo"+i).show(); alert("#thumbInfo"+i); });
  $("#thumbInfo"+i+" .xbutton").click(function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); });
});
Sign up to request clarification or add additional context in comments.

Comments

3

use a closure in your for iteration:

for (var i = 0, len = sites.length ; i < len ; i++)
{
    (function(i) {
        $("#thumb"+i).click(function() {
            $("#shader").show(); 
            $("#thumbInfo"+i).show(); 
            alert("#thumbInfo"+i); 
        });
        $("#thumbInfo"+i+" .xbutton").click(function() { 
            $("#shader").hide(); 
            $("#thumbInfo"+i).hide(); 
        });
    }(i));
}

Comments

2

Place a function returning a function and parameterized by i outside the loop. JSLint will encourage you to do this anyway, and some might find it more readable to boot.

function make_fn1(i) {
    return function() { $("#shader").show(); $("#thumbInfo"+i).show(); };
}
function make_fn2(i) {
    return function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); };
}
for (var i = 0; i < sites.length ; i++)
{
    $("#thumb"+i).click(make_fn1(i));
    $("#thumbInfo"+i+" .xbutton").click(make_fn2(i));
}

However, this could be cleaned up in other ways. For starters, as long as you're using jQuery, $("#shader, #thumbInfo"+i).show(); is more concise. Furthermore, in the current code the notion that the two functions either hide or show the same two elements is not factored out, so could be

function make_fn (i,showhide) {
    return function() { $("#shader, #thumbInfo"+i)[showhide]() };
}
for (var i = 0; i < sites.length ; i++)
{
    $("#thumb"+i).click(make_fn(i,'show'));
    $("#thumbInfo"+i+" .xbutton").click(make_fn(i,'hide'));
}

Comments

-1
var len = sites.length ;
for (var i = 0; i < len ; i++)
    {
      $("#thumb"+i).click(function() { $("#shader").show(); $("#thumbInfo"+i).show(); alert("#thumbInfo"+i); });
      $("#thumbInfo"+i+" .xbutton").click(function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); });
    }

you might have been assigning 5 to i;

2 Comments

No, the closure gives access to the parent's variable i, which by the time the click() event is called, has beens set to 5.
I can certify that this answer is incorrect. I will leave it here for reference.

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.