Solved

Javascript - references / pointers to objects problem

Posted on 2009-03-29
5
175 Views
Last Modified: 2012-05-06
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
Comment
Question by:debussy007
  • 3
  • 2
5 Comments
 
LVL 13

Expert Comment

by:numberkruncher
ID: 24014929
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
 

Author Comment

by:debussy007
ID: 24027661
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
 
LVL 13

Accepted Solution

by:
numberkruncher earned 115 total points
ID: 24027874
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
 

Author Comment

by:debussy007
ID: 24028316
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
 
LVL 13

Expert Comment

by:numberkruncher
ID: 24028538
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

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

In Part 1 (http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/A_7849-Hex-Maze.html) we covered the hexagonal maze basics -- how the cells are represented in a JavaScript array and how the maze is displayed.  In this part, we'…
International Data Corporation (IDC) prognosticates that before the current the year gets over disbursing on IT framework products to be sent in cloud environs will be $37.1B.
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now