3

This is a really basic question but...

I have some code like this

var arr = Array('blah.jpg','ha.jpg');
for (var i=0; i<array.length; i++)
{
    $('div#blah' + i).click(function() {
           $('img').attr('src', arr[i]); });
}

This should bind the div with id="blah0" to change all images to 'blah.jpg' when clicked. Similarly, clicking the div with id ="blah1" should change all images to 'ha.jpg'.

However, the anonymous function won't work because it will use the value of 'i' at the time of execution, i.e. 2. This means that clicking either div will try and set all images to arr[2] - a non-existent element (interestingly not throwing a JS error on my machine but that's another story...).

How can I get the anonymous function to be created using the value of 'i' at declaration time?

As a simpler example:

for (var i=0; i<10; i++)
{
    $('div#blah'+i).click(function() {
       alert(i)); });
}

This should display '0' when I click 'blah0', '1' when I click 'blah1' etc.

However, by default it will display '10' no matter which 'blah' i click.

4 Answers 4

5

Declare a new variable inside a function that creates a new click handler that gets the current value of i as a parameter:

function makeClickHandler(arr, local_i) {
    return function() {
        $('img').attr('src', arr[local_i]);
    };
}

var arr = Array('blah.jpg','ha.jpg');
for (var i=0; i<array.length; i++)
{
    $('div#blah' + i).click(makeClickHandler(arr, i));
}

Each instance of the function gets its own copy of local_i, that doesn't change each time.

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

Comments

4

In this particular case you should be using a closure:

for (var i=0; i<10; i++)
{
    (function(j){
        $('div#blah'+j).click(function() { alert(j)); });
    })(i);        
}

(function(){ /* code */ })() denotes a self executing function, which implies that it will use and evaluate the value of i immediately in the loop as opposed to at click time.

Comments

0

Have 1 more variable inside the loop and increment it after using it in the closure.


var j = 0;
for (var i=0; i<array.length; i++)
{
    $('div#blah' + j).click(function() {
           $('img').attr('src', arr[i]); });

    j++;
}

3 Comments

The problem isn't binding (i.e. 'div#blah' + j) but the array access (i.e. arr[i]). In the method you use, there will be no difference at all - the click will still call call the 'i'th element of arr using the value of i at that time (e.g. array.length) not the value of i when i made the function
While I don't understand much of closure, you could let the click to call a single function & check the Event.Src (which will give you div1, div2 or div3), extract the id from it and based on that set the image source.
Your second option could probably work. Not sure on new function() {}.
0

I have this answer so far but bit of a hack:

var arr = Array('blah.jpg','ha.jpg');
for (var i=0; i<array.length; i++)
{
    eval("$('div#blah' + i).click(function() { $('img').attr('src', arr[" + i + "]); })");
}

Also:

for (var i=0; i<10; i++)
{
    eval("$('div#blah'+i).click(function() { alert(" + i + ")); });");
}

1 Comment

Could also use the multiline hack as here forums.whirlpool.net.au/forum-replies-archive.cfm/487804.html if too long to single line eval.

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.