{ "id": "104904", "key": "AC-1898", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "12217", "key": "AC", "name": "Appcelerator - INBOX", "projectCategory": { "id": "10000", "description": "", "name": "Customer Service" } }, "resolution": { "id": "7", "description": "", "name": "Invalid" }, "resolutiondate": "2012-11-21T00:45:56.000+0000", "created": "2012-11-13T21:06:51.000+0000", "labels": [], "versions": [], "issuelinks": [], "assignee": { "name": "mpmiranda", "key": "mpmiranda", "displayName": "Mauro Parra-Miranda", "active": true, "timeZone": "America/Mexico_City" }, "updated": "2016-03-08T07:40:49.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [], "description": "Titanium seems to be overwriting loop variables even if used within the inner function.\r\n\r\nExample:\r\n{code}\r\nvar window = Ti.ui.createWindow({height: 400, width: 329});\r\nvar test = ['This', 'is', 'a', 'test'];\r\nvar top = 0;\r\nfor (var x in test) {\r\n\tvar view = Ti.UI.createView({top: top, left: 0, width: 320, height: 10, backgroundColor: 'blue'});\r\n\tvar current = test[x];\r\n\ttop += 15;\r\n\tview.addEventListener('click', function() {\r\n\t\talert(current);\r\n\t});\r\n\twindow.add(view);\r\n}\r\nwindow.open();\r\n\r\n{code}\r\n\r\nYou would expect each view to alert its corresponding word, but they all alert 'test'.\r\n\r\nThe workaround so far is to add that property to the view itself:\r\n\r\n{code}\r\nvar window = Ti.ui.createWindow({height: 400, width: 329});\r\nvar test = ['This', 'is', 'a', 'test'];\r\nvar top = 0;\r\nfor (var x in test) {\r\n\tvar view = Ti.UI.createView({top: top, left: 0, width: 320, height: 10, backgroundColor: 'blue', text: test[x]});\r\n\ttop += 15;\r\n\tview.addEventListener('click', function() {\r\n\t\talert(this.text);\r\n\t});\r\n\twindow.add(view);\r\n}\r\nwindow.open();\r\n\r\n{code}\r\n\r\nI should also note that if I use \"alert(view.text)\" instead of \"alert(this.text)\", it still always says \"test\" (for the same reason, except the view variable).", "attachment": [], "flagged": false, "summary": "Titanium Scope Issues", "creator": { "name": "jkoett", "key": "jkoett", "displayName": "Joel Koett", "active": true, "timeZone": "America/Los_Angeles" }, "subtasks": [], "reporter": { "name": "jkoett", "key": "jkoett", "displayName": "Joel Koett", "active": true, "timeZone": "America/Los_Angeles" }, "environment": null, "comment": { "comments": [ { "id": "228120", "author": { "name": "dsefton", "key": "dsefton", "displayName": "Daniel Sefton", "active": true, "timeZone": "America/Los_Angeles" }, "body": "\"current\" is being created in the global scope, hence why it gets replaced every time. A for-loop is not a function, it does not create its own scope. This is how Javascript works, it's not a Titanium issue.", "updateAuthor": { "name": "dsefton", "key": "dsefton", "displayName": "Daniel Sefton", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-11-21T00:45:56.000+0000", "updated": "2012-11-21T00:45:56.000+0000" }, { "id": "228121", "author": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "body": "As Daniel mentioned, JavaScript does not have block level scope, so view and current are actually global scope, not for-in scope. The callback function won't be executed until the current thread of execution has finished, meaning that the view and current variables will be whatever their last value was ('test' in this case since the variable is global scope).\r\n\r\nYour workaround is one way of doing it, although I would recommend another:\r\n{code}\r\nvar window = Ti.ui.createWindow({height: 400, width: 329}),\r\n test = ['This', 'is', 'a', 'test'],\r\n top = 0,\r\ntest.forEach(function (current) {\r\n var view = Ti.UI.createView({top: top, left: 0, width: 320, height: 10, backgroundColor: 'blue'});\r\n top += 15;\r\n view.addEventListener('click', function() {\r\n alert(current);\r\n });\r\n window.add(view);\r\n});\r\nwindow.open();\r\n{code}\r\nThe forEach creates a new context for each element in test and \"locks\" the value of current in place.\r\n\r\nA bit of advice: always declare your variables at the top of a function/module (C style) so that you avoid logic errors like this one.\r\n\r\nFor a more in-depth discussion of variable hoisting (the whole variables declared at top thing), check out http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting", "updateAuthor": { "name": "bhughes", "key": "bhughes", "displayName": "Bryan Hughes", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2012-11-21T00:57:34.000+0000", "updated": "2012-11-21T01:00:29.000+0000" }, { "id": "280968", "author": { "name": "mpmiranda", "key": "mpmiranda", "displayName": "Mauro Parra-Miranda", "active": true, "timeZone": "America/Mexico_City" }, "body": "Invalid issue. ", "updateAuthor": { "name": "mpmiranda", "key": "mpmiranda", "displayName": "Mauro Parra-Miranda", "active": true, "timeZone": "America/Mexico_City" }, "created": "2013-11-24T22:18:25.000+0000", "updated": "2013-11-24T22:18:25.000+0000" } ], "maxResults": 3, "total": 3, "startAt": 0 } } }