Flex: Variables, Anonymous Functions, and For Loops
I just ran into some weird behaviour involving a for loop, some variables, and a bunch ofanonymous functions. This is in Actionscript 3.0 using Flex SDK 3.4 and current Google Maps API(as of the date of this post&mdash I read somewhere they're rolling out a new version although it's not really relevant for this post)
So below I have a function that loops through the xml result of an http service, for each item in the result it creates a marker on a map and gives that marker a click event. When you click on a given marker I want a window to pop up with the name and description of that location, so the following is the code you'd expect to write. For simplicity sake you can keep an eye on the i:int variable which will help clarify the issue.
//trace(i) will always output total items in the xml result private function processResult(event:ResultEvent):void { var total:int = event.result.data.item.length; for (var i:int = 0; i<total; i++) { var item:Object = event.result.data.item[i]; //this will create the marker object var marker = new Marker(new LatLng(item.lat, item.lng), new MarkerOptions({fillStyle: {color: 0xEE9C21}, radius: 7, tooltip: item.name})); marker.addEventListener(MapMouseEvent.CLICK, function():void { //this will open an info window when the marker is clicked map.openInfoWindow(map.getCenter(), new InfoWindowOptions({hasTail: true, tailHeight: 5, hasShadow: true, title:item.name, contentHTML:item.description})); trace(i); }); map.addOverlay(marker); } }
Now what you'll find with the above code is that no matter which placemark you click on, they will all show the same name and description. Say that there are 5 items in the xml result, tracing i will output the number 5.
If you're new to programming, yes i will be 0 during the for loop's first run. Yes having 5 items and starting at 0 means it should be 4 for the last run, but the value of i increments one last time to make the i<totalcondition false before it exits the loop, so essentially it uses the final value of i for all the placemarks which is 5.
I can't see any reason why this should be happening other than language or framework immaturity.
The solution; or I should say the easiest, quickest solution, is to create an external function for marker creation that is called by the for loop, which for clarity's sake will only contain the part that's required to explain the concept and make it work ie: adding an event listener to the marker, but in the real world should have all the code necessary for creating a marker - that way you'd have an independent marker creation function you could call from anywhere in the application. Below is the working code:
//trace(i) will output the correct index depending on the placemark clicked private function processResult(event:ResultEvent):void { var total:int = event.result.data.item.length; for (var i:int = 0; i<total; i++) { var item:Object = event.result.data.item[i]; var marker = new Marker(new LatLng(item.lat, item.lng), new MarkerOptions({fillStyle: {color: 0xEE9C21}, radius: 7, tooltip: item.name})); //call external function and pass variables to it placeMarkerAddClickEventListener(marker, item.name, item.description); map.addOverlay(marker); } } //external function private function placeMarkerAddClickEventListener(marker:Marker, name:String, description:String):void { marker.addEventListener(MapMouseEvent.CLICK, function():void { map.openInfoWindow(map.getCenter(), new InfoWindowOptions({hasTail: true, tailHeight: 5, hasShadow: true, title:name, contentHTML:description})); }); }
Leave a Comment | Sep 23, 2009