1

Possible Duplicate:
Event handlers inside a Javascript loop - need a closure?

I have been trying to get this to work for a while and decided to just ask.

I have the following:

function doSomething(var1, var2) {
    dojo.xhrGet({
        url:"somUrl",
        content: {value1:var1,value2:var2},
        preventCache: true,
        handleAs:"json",
        load: function(response){
            for(var i in response.myObject) {
                var listItem = new dojox.mobile.ListItem({
                    label: response.myObject[i].name,
                    rightText: response.myObject[i].value,
                    clickable: true, 
                    onClick: function() {
                        customFunction(response.myObject[i]);
                        this.transitionTo("someScreen");
                    }   
                });
                myList.addChild(listItem);
            }               
        },
        error:function(e){alert(e);}
    });
}
doSomething(myVal1, myVal2);

The line that says customFunction(response.myObject[i]); always returns the last object in the myObject arrray.

Can someone help me with the syntax so I can make this work correctly? I've been reading about js closures and callbacks but I just can't get it to work.

Thanks

Community
  • 1
  • 1
blong824
  • 3,920
  • 14
  • 54
  • 75
  • 2
    You can save yourself a lot of time by paying attention to the possible duplicate questions that Stackoverflow automatically shows you when you're trying to ask a new one. This issue in particular is covered by many many previous questions. – Pointy Nov 16 '11 at 20:37

2 Answers2

3

You need an additional wrapper function

onClick: (function(obj) {
    return function() {
        customFunction(obj);
        this.transitionTo("someScreen");
    };
})(response.myObject[i])

See this answer for an explanation:

JavaScript's scopes are function-level, not block-level, and creating a closure just means that the enclosing scope gets added to the lexical environment of the enclosed function.

After the loop terminates, the function-level variable i has the value 5 [note: or, in this case, the name of the last property in response.myObject], and that's what the inner function 'sees'.

Community
  • 1
  • 1
Christoph
  • 164,997
  • 36
  • 182
  • 240
2

You need to ensure that i is contained in a closure in each iteration of the for-loop:

[...]
  load: function(response){
        for(var i in response.myObject) {
            var listItem = new dojox.mobile.ListItem({
                label: response.myObject[i].name,
                rightText: response.myObject[i].value,
                clickable: true, 
                onClick: (function(inner) {
                    return function (clickEvent) {
                      customFunction(response.myObject[inner]);
                      this.transitionTo("someScreen");
                    }
                }(i))   
            });
            myList.addChild(listItem);
        }               
    }
 [...]
PatrikAkerstrand
  • 45,315
  • 11
  • 79
  • 94
  • Now if only JS had better scoping options defined in the core language. – ChaosPandion Nov 16 '11 at 20:40
  • @ChaosPandion: "JS 1.7" has `let` blocks and statements – newacct Nov 16 '11 at 21:44
  • @newacct: it's also in the ES.next draft ( http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts ), ie the next ECMA edition will probably make it official... – Christoph Nov 16 '11 at 22:25
  • @newacct - I am aware of `let` in JavaScript. What I should have said was ECMAScript. Logically you really can't use `let` unless you are targeting JavaScript only. – ChaosPandion Nov 16 '11 at 23:09