3

i have the following code :

$(document).ready(function () {
    for (i = 1; i <= number_of_banners; i++) {
    var selector = "#link_" + i;
    $(selector).click(function () {
        alert(i);
        });
    }
});

but the alert() can't get the "i" variable from the for loop. How can I use the i variable of for loop inside the .click function ?

Kozet
  • 1,103
  • 1
  • 11
  • 19
  • A classical one:) I guess this has been asked a dozen times on SO. – Christoph Sep 18 '12 at 06:05
  • 1
    The problem you're having is that the `.click()` handlers _are_ using the `i` variable from the for loop - but all of them are referencing the same, _live_ `i` variable and by the time clicks occur the for loop has completed and `i` is equal to `number_of_banners`. (Only a dozen @Christoph? Probably at least a dozen this month...) – nnnnnn Sep 18 '12 at 06:07
  • possible duplicate of [Assign click handlers in for loop](http://stackoverflow.com/questions/4091765/assign-click-handlers-in-for-loop) – givanse Feb 10 '14 at 22:14

5 Answers5

5

you can use this code :

$(document).ready(function () {
    for (var i = 1; i <= number_of_banners; i++) {
        var selector = "#link_" + i;
        $(selector).on('click', {id: i}, function (e) {
            alert(e.data.id);
        });
    }
});

you should use on method and use click argument in it instead of using onclick method

Mehran Abbasi
  • 103
  • 1
  • 6
4

Using jQuery .on(event, data, handler) you can do it easily.

$(document).ready(function () {
    for (var i = 1; i <= number_of_banners; i++) {
        var selector = "#link_" + i;
        $(selector).on('click', {id: i}, function (e) {
            alert(e.data.id);
        });
    }
});

Working sample

thecodeparadox
  • 86,271
  • 21
  • 138
  • 164
3

Might this happen be due the fact of the JavaScript hoisting JavaScript Scoping mechanism??

For instance:

doesn't work as JavaScript uses function scope rather than block scope as we're usually accustomed from other languages like Java and C#. In order to make it work, one has to create a new scope by explicitly creating a new anonymous function which then binds the according variable:

I know this doesn't directly answer the question above, but might still be useful though for others stumbling over this question.

Juri
  • 32,424
  • 20
  • 102
  • 136
  • 1
    It's not a hoisting issue, and the scoping issues discussed in the article you link to don't really cover it either. It's more a closure issue (noting though that `i` is global in the question), and your second fiddle illustrates one way to get it to work - why don't you update your answer to talk about _why_ it works? – nnnnnn Sep 18 '12 at 06:12
  • @nnnnnn Uhps, sorry, you're right. As I just quickly posted this answer I wrongly added the hoisting stuff, which of course is more a scoping problem (due to the JavaScript function rather than block scope) as you correctly mentioned. I'll update my answer – Juri Sep 18 '12 at 21:49
  • +1 for the second example of variable binding...... Though an answer that mentions hoisting shouldn't have var statements anywhere but on the first line of a function ;) – Peter Ajtai Oct 24 '12 at 06:24
1

I think you can pass it as a parameter into the anonymous function as long as the function is declared within a scope that can access i.

function (i) {
   alert(i);
}
Jonathon Ashworth
  • 1,182
  • 10
  • 20
  • That won't work: that function is a callback for the click handler, and jQuery doesn't know to pass that `i` value in when it calls the function. – nnnnnn Sep 18 '12 at 06:06
  • @nnn it may work if he puts the func around the handler binding and not inside. – Christoph Sep 18 '12 at 06:48
1

a quick solution would be to use the eventData and store the current i in that:

$(document).ready(function () {
    for (var i = 1; i <= number_of_banners; i++) {
        var selector = "#link_" + i;
        $(selector).bind('click', i, function (e) {
            alert(e.data);
        });
    }
});

if you are using jquery 1.7+ then use on instead of bind

voigtan
  • 8,953
  • 2
  • 29
  • 30