I wrote some javascript to run through an array of "modules". For each module it makes an ajax call, gets the html for the module, and dumps the module into one of two columns on the page layout.
var modules = [
{ name: 'ExchangeStatus', title: 'Exchange Status', column: 'left' },
{ name: 'Grid', title: 'Contacts', column: 'right' }
{ name: 'Filters', title: 'Filters', column: 'left' }
],
modulesUrl = '/Modules/';
for (var count = 0; count < modules.length; count++) {
var module = modules[count];
// Get module HTML.
$.ajax({
url: modulesUrl + module.name,
success: function (moduleHtml) {
// Append module HTML to appropriate element.
$('#' + module.column + 'Column').append(moduleHtml);
// Custom event to trigger the module to load its data.
var initializeModuleEvent = $.Event('initialize' + module.name);
initializeModuleEvent.firstLoad = true;
$(document).trigger(initializeModuleEvent);
}
});
}
Problem with this is that the for loop creates a race condition. In the ajax callback module.column
is almost always the value of the last module because the for loop finishes long before the ajax callbacks return. How can I maintain the module variable so that each callback is dealing with the appropriate module? Currently all three modules end up in the left column because the last module in the loop is in the left column.
I wrote some javascript to run through an array of "modules". For each module it makes an ajax call, gets the html for the module, and dumps the module into one of two columns on the page layout.
var modules = [
{ name: 'ExchangeStatus', title: 'Exchange Status', column: 'left' },
{ name: 'Grid', title: 'Contacts', column: 'right' }
{ name: 'Filters', title: 'Filters', column: 'left' }
],
modulesUrl = '/Modules/';
for (var count = 0; count < modules.length; count++) {
var module = modules[count];
// Get module HTML.
$.ajax({
url: modulesUrl + module.name,
success: function (moduleHtml) {
// Append module HTML to appropriate element.
$('#' + module.column + 'Column').append(moduleHtml);
// Custom event to trigger the module to load its data.
var initializeModuleEvent = $.Event('initialize' + module.name);
initializeModuleEvent.firstLoad = true;
$(document).trigger(initializeModuleEvent);
}
});
}
Problem with this is that the for loop creates a race condition. In the ajax callback module.column
is almost always the value of the last module because the for loop finishes long before the ajax callbacks return. How can I maintain the module variable so that each callback is dealing with the appropriate module? Currently all three modules end up in the left column because the last module in the loop is in the left column.
- possible duplicate of Javascript closure inside loops - simple practical example – Felix Kling Commented Jan 31, 2013 at 23:38
5 Answers
Reset to default 7You could try creating an extra scope to pass module
:
for (var count = 0; count < modules.length; count++) {
var module = modules[count];
(function(module) {
$.ajax({
...
})
}(module));
Edit: If you want you can use forEach
as well:
modules.forEach(function(module) {
// 'module' will be available everywhere in this scope
});
Modify your success callback to this:
$.ajax({
url: modulesUrl + module.name,
success: (function (module) {
return function (moduleHtml) {
// Append module HTML to appropriate element.
$('#' + module.column + 'Column').append(moduleHtml);
// Custom event to trigger the module to load its data.
var initializeModuleEvent = $.Event('initialize' + module.name);
initializeModuleEvent.firstLoad = true;
$(document).trigger(initializeModuleEvent);
};
}(module));
});
This will create a new scope for the appropriate module
variable value.
There's no need to wrap the entire ajax
call here.
instead of using the for loop use the jquery's each.. this will solve the problem
var modules = [
{ name: 'ExchangeStatus', title: 'Exchange Status', column: 'left' },
{ name: 'Grid', title: 'Contacts', column: 'right' }
{ name: 'Filters', title: 'Filters', column: 'left' }
],
modulesUrl = '/Modules/';
$(modules).each( function(index, elem)
{
var module = elem;
// Get module HTML.
$.ajax({
url: modulesUrl + module.name,
success: function (moduleHtml) {
// Append module HTML to appropriate element.
$('#' + module.column + 'Column').append(moduleHtml);
// Custom event to trigger the module to load its data.
var initializeModuleEvent = $.Event('initialize' + module.name);
initializeModuleEvent.firstLoad = true;
$(document).trigger(initializeModuleEvent);
}
});
}
}
);
That would help
for (var count = 0; count < modules.length; count++) {
var module = modules[count];
(function (module) {
// Get module HTML.
$.ajax({
url: modulesUrl + module.name,
success: function (moduleHtml) {
// Append module HTML to appropriate element.
$('#' + module.column + 'Column').append(moduleHtml);
// Custom event to trigger the module to load its data.
var initia`enter code here`lizeModuleEvent = $.Event('initialize' + module.name);
initializeModuleEvent.firstLoad = true;
$(document).trigger(initializeModuleEvent);
}
});
})(module)
}
Try this way and tell me if it works!
for (var n = 0; n < modules.length; n++) {
(function () {
var i = n;
var module = modules[i];
// Get module HTML.
$.ajax({
url: modulesUrl + module.name,
success: function (moduleHtml) {
// Append module HTML to appropriate element.
$('#' + module.column + 'Column').append(moduleHtml);
// Custom event to trigger the module to load its data.
var initializeModuleEvent = $.Event('initialize' + module.name);
initializeModuleEvent.firstLoad = true;
$(document).trigger(initializeModuleEvent);
}
});
} ());
}