0

I know this kind of question gets asked alot, but I still haven't been able to find a way to make this work correctly.

The code:

function doStuff () {
 for (var i = 0; i< elementsList.length; i++) {
 elementsList[i].previousSibling.lastChild.addEventListener("click", function(){
 toggle(elementsList[i])}, false);
 }
 } // ends function
 function toggle (element) {
 alert (element);
 }

The problem is in passing variables to the toggle function. It works with the this keyword (but that sends a reference to the clicked item, which in this case is useless), but not with elementsList[i] which alerts as undefined in Firefox.

As I understood it, using anonymous functions to call a function is enough to deal with closure problems, so what have I missed?

asked Jul 4, 2011 at 8:24
3

4 Answers 4

3

Try:

function startOfFunction() {
 for (var i = 0; i< elementsList.length; i++) {
 elementsList[i].previousSibling.lastChild.addEventListener(
 "click",
 (function(el){return function(){toggle(el);};})(elementsList[i]),
 false
 );
 }
} // ends function
function toggle (element) {
 alert (element);
}
answered Jul 4, 2011 at 8:30
Sign up to request clarification or add additional context in comments.

1 Comment

As japrescott said, you're referencing the variable i in the event handler. This is incremented further in the outer loop before the event handler is executed. By using the closure the variable i is evaluated at the time (inside the loop), meaning it's value in the event handler is fixed.
1

The Problem is, that you want to use the var i! i is available in the onClick Event, (since closure and stuff). Since you have a loop, i is counted up. Now, if you click on any of the elements, i will always be elementsList.length (since all event functions access the same i )!

using the solution of Matt will work.

answered Jul 4, 2011 at 8:35

Comments

1

As an explanation: the anonymous function you use in the for loop references the variable "i" to get the element to toggle. As anonymous functions use the "live" value of the variable, when somebody clicks the element, "i" will always be elementsList.length+1.

The code example from Matt solves this by sticking the i into another function in which it is "fixated". This always holds true:

If you iterate over elements attaching events, do not use simple anonymous functions as they screw up, but rather create a new function for each element. The more readable version of Matts answer would be:

function iterate () {
 for (var i = 0; i < list.length; i++) {
 // In here, i changes, so list[i] changes all the time, too. Pass it on!
 list[i].addEventListener(createEventFunction(list[i]);
 }
 }
 function createEventFunction (item) {
 // In here, item is fixed as it is passed as a function parameter.
 return function (event) {
 alert(item);
 };
 }
answered Jul 4, 2011 at 8:39

Comments

0

Try:

function doStuff () {
 for (var i = 0; i< elementsList.length; i++) {
 (function(x) {
 elementsList[x].previousSibling.lastChild.addEventListener("click", function(){
 toggle(elementsList[x])}, false);
 })(i);
 }
} // ends function

I think it might be an issue with passing elementsList[i] around, so the above code has a closure which should help.

answered Jul 4, 2011 at 8:33

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.