• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 189
  • Last Modified:

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!
0
debussy007
Asked:
debussy007
  • 3
  • 2
1 Solution
 
numberkruncherCommented:
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

0
 
debussy007Author Commented:
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.
0
 
numberkruncherCommented:
You can create a closure when you place a function inside a function.

I will try to walk you through an example. Take a look at SOURCE #1 below. This is a straight-forward function "foo" which sets up a variable called "myVariable", does something with it, and then finishes. This variable is stored within the calling context of "foo", and is only available during that time. Once "foo" has finished, the variable is no longer available.

SOURCE #2 constructs a closure because its "myVariable" remains accessible even after "foo" has finished running. The function that is generated by "foo" remembers the state that "foo" was in at that exact time. So, when this generated function is called, it has access to the original "myVariable" instance.

SOURCE #2 then moves on to execute the generated function, and the value "12" appears in an alert box. The generated function is able to do this because it has access to the original variable.


So.......WHY? Why would we do this?

By creating a closure we were able to maintain each key, as opposed to just the last one.


Here is a website which might help explain it more clearly:

http://blog.morrisjohns.com/javascript_closures_for_dummies
// SOURCE #1
 
function foo()
{
   // Set up a variable in the context of "foo".
   var myVariable = 12;
   // Variable can then be used.
   alert(myVariable);
}
// "myVariable" is not available outside of function "foo".
 
 
// SOURCE #2
 
function foo()
{
   // Set up a variable in the context of "foo".
   var myVariable = 12;
 
   // Define and return a new function.
   return function() {
       // "myVariable" is still available event after "foo" has finished.
       alert(myVariable);
   }
}
 
// Use foo to get the generated function.
var bar = foo();
 
// Now if we call "bar", the variable gets displayed on screen.
bar();

Open in new window

0
 
debussy007Author Commented:
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.
0
 
numberkruncherCommented:
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.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now