Link to home
Start Free TrialLog in
Avatar of debussy007
debussy007

asked on

Javascript - references / pointers to objects problem

Hi,

I add Google Maps Markers on a map, and want to bind a click event on each of them: I add the markers on the map in a loop, so the binding of the event is done in the loop for each marker.
But it seems that when I click on the markers on the map, the callback function will execute the same instructions for all the markers: the instructions that have been set for the last marker.
It seems to be a problem with the references ...
Here is code to make it all clear:

for(key in data) {
      [...]
      var pointDep = new GLatLng(data[key][2], data[key][1]);
      var markerDep = new GMarker(pointDep, icon);
      alert(data[key][6]);
      GEvent.addListener(markerDep, "click", function() {
            alert(data[key][6]);
      });
      [...]
}

When loading the page, the first alert will for example display:
A
B
C
D

And the alert inside the event listener will only display D when I click on any marker. I was expecting respectively to get alerts of A, B, C and D.

They need to acheive the same in this tutorial:
http://code.google.com/intl/fr/apis/maps/documentation/events.html#Event_Closures
(Using Closures in Event Listeners)
They also add the markers via a loop, so I can't understand why my code doesn't work and their does. Some difference somewhere ...

Thank you for any help!
Avatar of numberkruncher
numberkruncher
Flag of United Kingdom of Great Britain and Northern Ireland image

Here is an example of how to create a closure. The example is on a simple loop between 3 numbers. Try the example as it is, and then have a go with the non-bound function.

For a more complete events and function binding system I would strongly recommend the Prototype Framework for JavaScript (3rd example in source). http://www.prototypejs.org
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Demo Page</title>
		<script type="text/javascript">
			// A simple bind function which creates a closure.
			function bind(fn, context, data) {
				return function() {
					return fn.call(context, data);
				};
			}
 
			// Array to store bound functions.
			var c = [];
			// Iterate through a sequence of numbers.
			for (var i = 0; i < 3; ++i) {
				c.push(bind(function(data) {
					// Display the bound data, in this example the value of "i".
					alert(data);
				}, this, i));
 
				// Replace the above with the following to see the non-bound version:
				//c.push(function() {
				//	alert(i);
				//});
 
				// The following shows how simple this would be with PrototypeJS:
				// Note: You will need Protoype for this to work!
				//c.push(function(data) {
				//	alert(data);
				//}.bind(i));
			}
 
			// Call each of the bound functions in turn.
			c[0]();
			c[1]();
			c[2]();
		</script>
	</head>
	<body>
		<h1>Demo Page</h1>
		<div>
		</div>
	</body>
</html>

Open in new window

Avatar of debussy007
debussy007

ASKER

I would like to udnerstand the problem of my code, to get a little smarter.
Also, I don't know what a closure is.

Thanks.
ASKER CERTIFIED SOLUTION
Avatar of numberkruncher
numberkruncher
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I think I get you ...

And what would be the "normal" way to do this without the closures ?
E.g. never heard about closures in other languages.
Other languages deal with events in a different way. Usually the code which fires an event handler has access to the event arguments, and can provide them there and then.

When you bind a DOM event in JavaScript you need a mechanism to associate information with each event handler. One of the simplest ways of doing this in JavaScript is to construct a closure. Closures are an extremely powerful asset of JavaScript, especially if you want to emulate things like classes and namespaces.

As far as I am aware, closures are the only realistic way to achieve this in JavaScript. The only other way that I know of would be to create a lookup table, but this could damage performance, and would be a lot more difficult to manage.