Reputation: 5993
I have a basic closure / "working with closures" JavaScript question.
I have, in a function and inside two for loops, an Ajax call I want to make with a variable equal to what it was inside the loop. matches_date is set to a JavaScript date with a custom-modified setTime() that is different each time it goes through the loop. Inside the inner loop I have:
jQuery('.hide-instance').click(function(event)
{
jQuery.ajax('/save/hide/instance', {'complete': function()
{
jQuery.ajax('/load/calendar', {'complete':
DASHBOARD.load_calendar_from_ajax, 'type': 'POST'});
}, 'data':
{
'id': element.id,
'date': matches_date.toDateString()
}, 'type': 'POST'});
});
This is, predictably enough, resulting on the hide-instance checkboxes calling the function with 'date' in the hash equal to the last run through the loop's calling toDateString() on the last value of matches_date in the loop.
I've tried copying matches_date.toDateString() to a var declared just before the function, but it doesn't have the same effect.
How can I change my code so that 'date' in the dictionary is populated with the toDateString() value for the loop iteration it was defined in?
--EDIT--
The call quoted above is inside two nested loops inside a function:
DASHBOARD.load_calendar = function(json)
{
console.log('Loading calendar...');
DASHBOARD.calendar_entries = JSON.parse(json);
var last_unique_event = 0;
var is_unique = false;
var last_day_displayed = '';
jQuery('#display').html('');
for(var days_difference = 0; days_difference - last_unique_event <
DASHBOARD.calendar_days; ++days_difference)
{
var matches_date = new Date();
matches_date.setTime(matches_date.getTime() + days_difference * 24 * 60 *
60 * 1000);
for(var index = 0; index < DASHBOARD.calendar_entries.length; ++index)
{
P.S. I see a way to do it with an eval() on code I would build myself, so it would not be an eval() on untrusted code, but as a rule if the only way I see to do something is with an eval(), 99% of the time that's a clue to try to find the correct way of doing something.
Upvotes: 1
Views: 36
Reputation: 18344
By adding a closure:
for(...){
var matches_date = ...
(function(matches_date){ //This line does the magic!
jQuery('.hide-instance').click(function(event)
{
jQuery.ajax('/save/hide/instance', {'complete': function()
{
jQuery.ajax('/load/calendar', {'complete':
DASHBOARD.load_calendar_from_ajax, 'type': 'POST'});
}, 'data':
{
'id': element.id,
'date': matches_date.toDateString()
}, 'type': 'POST'});
});
})(matches_date); //This one, too
}
As javascript vars scope is function-level, we add a function (closure) inside the loop with its own matches_date
var (as a param). This way the var is not shared, and each loop cycle has its own copy, so it doesn't get overwritten.
Cheers, from La Paz, Bolivia
Upvotes: 2