Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Event handlers inside a Javascript loop - need a closure?

I'm working with a bit of html and Javascript code that I've taken over from someone else. The page reloads a table of data (via an asynchronous request) every ten seconds, and then re-builds the table using some DOM code. The code in question looks something like this:

var blah = xmlres.getElementsByTagName('blah'); for(var i = 0; i < blah.length; i++) {     var td = document.createElement('td');     var select = document.createElement('select');     select.setAttribute("...", "...");     select.onchange = function() {         onStatusChanged(select, callid, anotherid);     };     td.appendChild(select); } 

When the onchange event is fired for a <select> element however, it seems like the same values are being passed to the onStatusChanged() method for every <select> in the table (I've verified that in each iteration of the loop, callid and anotherid are being given new, distinct values).

I suspect this is occuring because of the nature of how I am setting the event handler, with the select.onchange = function() syntax. If I understand how this is working correctly, this syntax sets a closure for the onchange event to be a function which refers to these two references, which end up having a final value of whatever they are set to on the last iteration of the loop. When the event fires, the value referenced by callid and anotherid is the value set in the last iteration, not the value set at the individual iteration.

Is there a way that I can copy the value of the parameters I am passing to onStatusChanged()?

I've changed the title to better reflect the question and the accepted answer.

like image 354
matt b Avatar asked Dec 04 '08 19:12

matt b


People also ask

How do event handlers work in JavaScript?

JavaScript Event HandlersEvent handlers can be used to handle and verify user input, user actions, and browser actions: Things that should be done every time a page loads. Things that should be done when the page is closed. Action that should be performed when a user clicks a button.

Why do we need closure in JavaScript?

In JavaScript, closures are the primary mechanism used to enable data privacy. When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can't get at the data from an outside scope except through the object's privileged methods.

Are all functions closures in JavaScript?

But as explained above, in JavaScript, all functions are naturally closures (there is only one exception, to be covered in The "new Function" syntax). That is: they automatically remember where they were created using a hidden [[Environment]] property, and then their code can access outer variables.

How does JavaScript event loop work?

The Event Loop has one simple job — to monitor the Call Stack and the Callback Queue. If the Call Stack is empty, the Event Loop will take the first event from the queue and will push it to the Call Stack, which effectively runs it. Such an iteration is called a tick in the Event Loop.


1 Answers

You do, indeed, need to implement a closure here. This should work (let me know - I didn't test it)

var blah = xmlres.getElementsByTagName('blah'); for(var i = 0; i < blah.length; i++) {     var td = document.createElement('td');     var select = document.createElement('select');     select.setAttribute("...", "...");     select.onchange = function(s,c,a)     {         return function()         {             onStatusChanged(s,c,a);         }     }(select, callid, anotherid);     td.appendChild(select); } 
like image 69
Peter Bailey Avatar answered Oct 01 '22 02:10

Peter Bailey