Mushy Mushy - 19 days ago 6
Javascript Question

using .ajax() in .each()

I'm trying to iterate through elements of .ball class and check if their associated url exists:

$(".ball").each(function(i){

var url;

var c_day = $(this).data('day');
var c_mon = $(this).data('mon');
var c_year = $(this).data('year');

url = c_year + "/" + c_mon + "/" + c_day + ".html";

$.ajax({

url: url,
error: function()
{
alert('file: ' + url + ' does not exist');
},
success: function()
{
alert('file: ' + url + 'EXXXXXXISTS!!!!!');
blogA[ blog_count ] = url;
blog_count++;
$(this).css("color", "red" );
}
});
});


I've done some research and read that using .ajax in .each causes a lot of problems but I couldn't wrap my head around on how to fix it.

The problem is that I get really weird results (has to do with asynchronous?). If I alert url outside of ajax, it correctly iterates through the elements. If I alert url in ajax, it spits out urls that belong to the last element of the class.

Answer

Something like this, in order to simplify your code

function successHandler(url, ball) {
  return function(ret) {
     alert('file: ' + url + 'EXXXXXXISTS!!!!!');
     ball.css('color','red')
  }
}

var balls = $('.ball'), requests = []


balls.each(function(index, ball) {
  var url = ...
  requests.push($.ajax({ url : url , success : successHandler(url, ball) })
})

$.when.apply($, requests).done(function() {
  alert('all balls are checked')
}) 

Or with ES6:

const success = (url,ball)=>(ret)=>ball.css('color','red')

const balls = $('.balls')
    , reqs = balls.map( (b, i) => {
        const url = ...
        return $.ajax({url, success:success(url,ball)})
    })

$.when.apply($, reqs).done( (resps) => alert('all done'))

A Little explanation: You are blindly using this in your callback, not knowing in which context it is going to be executed. In order to work around it and has your URL into callback we are creating function that returns a function, so it will have URL of current .ball DOM object in the context.

You'll probably also need to execute code after all ajax requests are done, so using $.when is the simplest way of doing it. And we are storing all promises just for this reason.