views:

115

answers:

4
for(n=0;n < 20;n++){
     $('#button' + n).click(function () { newAction(n); });
}

function newAction(x){
     alert(x);
}

The problem with this code is that when I press buttons their click actions somehow are not linked to their number, so by pressing button5 i may get alert 6 or something like that.

A: 

Try the following:

for(n=0;n < 20;n++){
     $('#button' + n).click(function (n) { newAction(n); });
}

function newAction(x){
     alert(x);
}

The reason is closures. When you don't pass the n along with the anonymous function, javascript looks for the variable in its own scope, and the parent scope. The parent scope has an 'n', but this n is the value of the n after the for loop. By passing along the n, you create a new n inside the scope of the function, and this one isn't changed when the for loop runs.

Marius
jQuery sends the first argument of click(function(e) {...});That would be the event object, not his userdefined variable.
Mister Lucky
A: 

i can think of easier ways to do what you are trying, but this'll work for you:

EDIT: Sorry i thought it was clear i was supplying a replacement for the line inside your loop. Here the entire functioning program

EDIT 2: Okay here's the outer $(document).ready() wrapper also that isn't even in the original question. This has been tested. this works. Even on 1.3+ .. It's the best answer given.

I've put up a functioning version of this program you can try out by visiting here

$(function() {
  for (n = 0; n < 20; n++){
    $('#button' + n).bind('click', n, function (e) { newAction(e.data); });
  }

});

function newAction(x){
  alert(x);
}
Scott Evernden
Are you missing something? This does not work for me using the 1.3x jQuery?
Mister Lucky
Even your edit would not work, the jQuery docs say you can pass the data that way. But it's not working if you wire this up in a real page and try it.
Mister Lucky
like i said in the edit, I thot it was obvious the one line i supplied went inside the FOR loop. The answer i've given works fine with 1.3.2. Dont quite understand the downvotes, since I think it's the best answer on this page so far
Scott Evernden
i wired up a real page and i really tried it and it really works. I assume you understand this all goes inside a $(document).ready() which even the original post didn't have?
Scott Evernden
you should use jQuery(function($){ }); to maximise effectiveness. Voted up because the 3-arg-bind does work, as per documented.
Kent Fredric
i am learning slowly that partial answers devoid of extra garnishment and frills do not gain you cred at SO. Of course I agree with your comment Kent, just wanted to get the correct answer up and be done with this :)
Scott Evernden
+3  A: 

This looks weird but this would be more appropriate way to create the closure so you can access the loop-scope variable per iteration...

  for(var n = 0; n < 20; n++) {
    $('#button' + n).click((function(i) {
      return function(e) { newAction(i) }
    })(n));
  }

  function newAction(x){
    alert(x);
  }
Mister Lucky
this is correct.
M. Utku ALTINKAYA
+3  A: 

Mr Lucky is on the right track, but his example I found a bit hard to read.

function button_bind( num ){ 
     $("#button" + num ).click(function(){
         newAction(num);
     });
}

for(var n = 0; n < 20; n++) {
     button_bind(n);
}

function newAction(x){
     alert(x);
}

This should clear up your scoping issue.

The above could be transformed to inline:

for(var n = 0; n < 20; n++) {

     (function(num){ 

        $("#button" + num ).click(function(){
         newAction(num);
        });

     })(n);

}

function newAction(x){
     alert(x);
}
Kent Fredric