views:

26

answers:

2

Dear StackOverflow: I have thoroughly researched this question and can't find a solution. Any help would be greatly appreciated.

I have a bunch of elements on a page, all of whose ID's are stored in an array called ids[].

I have initialized a third-party DOM script for each of these divs that detects when the element has been dragged. The next step is to assign a function to the onDrag event of each element.

For simplicity's sake, I'd simply like to show a popup dialog that states the ID of the element that was dragged. I am iterating through my array as follows:

for (i=0;i<ids.length;i++)
{
document.getElementById(ids[i]).onDrag = function(){alert(ids[i])}
}

This all seems well and good, but toggling the drag event of any of my elements causes a dialog to popup that states the ID of the last element in the array. In other words, it looks like the above function in my iteration is always being evaluated for the last index in my array. I feel like I am missing something very simple here but this issue is driving me nuts. Again, thanks for any help!

+1  A: 

Do the following changes,

for (...){
    SetOnDrag(ids[i]);
}

function SetOnDrag(id)
{
    document.getElementById(id).onDrag = function() { alert(id); };
}
A_Nablsi
Thanks, this worked like a charm.
Original Rockers
+1  A: 

The thing you've encountered is called closure and it is an essential part of Javascript.

A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).

What happens is that the anonymous function assigned to ondrag closes over it's environment including variable i. As a consequence whenever i changes outside of this function, i will contain the new value inside accordingly.

The way you can workaround this behavior in the current context is to create another scope with an additional self-executing function.

for (var i=0; i<ids.length; i++) {
  document.getElementById(ids[i]).onDrag = (function(i){  // <- i is a parameter
    return function() {
      alert(ids[i]);  // <- i will be the inner value saved from outside
    };
  })(i);  // <- invoke immidiately with the i from outside
}

You can read more on the topic: Use Cases for JavaScript Closures by @kangax

galambalazs
Very helpful explanation....I knew there was a key term that I was missing. Now I know to research closures. Thanks!
Original Rockers