1

What's wrong with this code? Reading this it seems that for each loop the jquery should attach a function with assigned values for each iteration. Instead it's attaching i = 2 to every object. Why is it doing that and how can I get it to attach the expected values (e.g., 0, 1, ...)?

//data.length is 2.

for (i=0; i<data.length; i++) {
    // Attach the click function
    linkId = 'a#' + pk;
    $(linkId).click(function(e) {
        e.preventDefault();
        console.log(i, pk, data);
    });
};

console.log -- each link has the same parameters

2 "52fef25e391a56206f03be6e" [object Array]
1
  • 2
    Classical closure+loop confusion. Commented Feb 15, 2014 at 21:25

4 Answers 4

2

You're assuming that a block creates a new variable scope. It doesn't in JavaScript. Only a function execution does.

If you use $.each() instead, the callback you give it will be invoked for each iteration, and so you'll have a new scope for every one.

$.each(data, function(i,item) {
                //    ^---^---function parameters are local to this scope

//   v--declare a variable local to this scope
    var linkId = 'a#' + pk;

                //   v--the function made in this scope can access the local vars
    $(linkId).click(function(e) {
        e.preventDefault();
        console.log(i, pk, data, linkId, data[i]);
    });
});
Sign up to request clarification or add additional context in comments.

2 Comments

This is very helpful and I've used your answer to solve my problem at hand. Thank you. However, for knowledge's sake, to get my original code to work, is it possible to declare variables within the scope of each iteration? I tried that but it didn't seem to work.
@TechMedicNYC: No, not without a function invocation of some sort. Blocks alone in JS simply don't define any type of variable scope. The next version of JS will have block scope by declaring variables with the let keyword. This is available today in Firefox as well as the newest versions of Chrome (when a flag is set) and I believe IE11.
2

console will be displayed only when you click the $(linkId) but at the time is is already equal to data.length (aka 2 in your case) so it will always display 2

Comments

0

Try to isolate the variable's scope. Declare a var j = i; inside the loop context so it enters the click-callback's scope.

Comments

0

So in order to create a separate scope for each iteration you can also use ordinary closure-functions, and pass current i into it:

for (var i = 0; i < data.length; i++) {
    (function(j) {
        $('a#' + pk).click(function(e) {
            e.preventDefault();
            console.log(j, pk, data);
        });
    })(i);
};

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.