I have the following code, which i’ve simplified, where $currEl gets logged and displays correctly, but in the $.ajax call it logs as null.
Am I missing something?
for(var i=0, j = atgSlots.length; i < j; i++) {
var currSlot = atgSlots[i].split('|'),
$currEl = currSlot[0].length ? $('[data-atg-url=' + currSlot[0] + ']') : null,
wcmLocation = currSlot[2] || null;
if ($currEl !== null && wcmLocation !== null) {
console.log($currEl);
$.ajax({
url: wcmLocation,
success: function(html) { console.log($currEl); updateSlots.setContent($currEl, html); },
error: updateSlots.checkDefault
}); // $.ajax
}
} // for : atgSlots
The problem is that your ajax success function has a live reference to the
$currElvariable, not a copy of it as of when the function was created. Consequently, all of those success handlers are referencing the same variable and therefore the same value — the last value assigned to$currElin the loop. Here’s a much, much simplified example of the same effect:That alerts “after”, not “before”, because the function that gets called after 10ms uses the current value of
a. See it in action.You can address this by giving each function its own variable to refer to, using an intermediary function. Here’s a minimalist change:
What that does is create and call a factory function on each loop, passing into the function the current value of
$currEl. That function then returns the function that should be used as the success handler. The success handler uses other information from the outer context (html, which I’m assuming should be common to all of them), but uses$thisEl(the function argument) instead of$currEl.It’s actually slightly inefficient to do it that way, because we create multiple identical copies of our new factory function. A less minimalist — and perhaps clearer — version would look like this:
(I’m assuming all of this code is contained inside a function somewhere.)
More about closures and this live reference thing in this blog post: “Closures are not complicated”.