javamonkey79
javamonkey79

Reputation: 17775

jquery collect from multiple ajax calls

I am trying to use jquery and ajax to collect data from several url's and then create content from that. However, I must be missing something as it does not seem to work.

I have something like this:

var html = "";
function loadByUrl(url) {
    $.ajax({
        url: url, 
        dataType: 'json',
        async: false,
        success: function(json) {
          $.each(json.data.children, function(i,item){
            if( someCondition ) {
                $(item.data).appendTo("#content");
            } else {
                html += "<div>" + item.data + "</div>"; 
            }
          }
        }
    });
}

loadByUrl("http://fake1.com");
loadByUrl("http://fake2.com");
loadByUrl("http://fake3.com");
$(html).appendTo("#content");

Basically, if some condition is met then I will add the content immediately, otherwise I'd like to add it at the end of the content with all of the other "saved off" content.

Is what I'm trying to do possible? If so, how?

Upvotes: 1

Views: 499

Answers (3)

Intelekshual
Intelekshual

Reputation: 7566

New answer:

I would approach this problem differently. Instead of using async: false, which is generally frowned upon (it's even deprecated in the latest version of jQuery), I would use $.when to achieve the same affect.

// return a promise
function loadByUrl(url) {
    return $.ajax({
        url: url, 
        dataType: 'json'
    });
}

// handle processing the data in a separate function
function processData(data) {
    var result = '';
    $.each(data.children, function(i,item){
        if( someCondition ) {
             $(item.data).appendTo("#content");
        } else {
            result += "<div>" + item.data + "</div>"; 
        }
    }
    return result;
}

// use when to ensure all of the AJAX requests execute before
// doing anything with their results
$.when(loadByUrl("http://fake1.com"), loadByUrl("http://fake2.com"), loadByUrl("http://fake3.com")).done(function(fake1, fake2, fake3) {
    // this function is called after all three AJAX promises are resolved
    var html = '';

    html += processData(fake1[0]);
    html += processData(fake2[0]);
    html += processData(fake3[0]);

    $(html).appendTo("#content");
});

Original answer:

The issue is $.ajax is asynchronous. Try replacing this line:

html += "<div>" + item.data + "</div>";

With this:

$("<div>" + item.data + "</div>").appendTo("#content");

Upvotes: 5

PJR
PJR

Reputation: 443

If its not a cross-domain call as Nir pointed out, try using ".done" with your ajax calls and do your appending within a callback function there.

Some thing like

$.ajax({
   your call setup and call
}).done(function(data) {
   console.log('Data:',data);  
   //your code to append the data 
}

This is possible with ".done" as the jqXHR objects returned by $.ajax() as of jQuery 1.5 implements the Promise pattern. You can check the documentation at http://api.jquery.com/jQuery.ajax/

Upvotes: 0

galdre
galdre

Reputation: 2339

EDIT: I just saw that these are synchronous requests. If you want to stick with synchronous requests, I think you want to check out this answer. I've never used the synchronous option, but I'm pretty sure you don't specify a callback function. If you don't mind switching to asynchronous, I think the code at the bottom of my answer would still work.

There are two places you are trying to append this content to the page. First, there's line 10:

$(item.data).appendTo("#content");

That should work just fine, assuming you write your condition how you like. The second place is the last line:

$(html).appendTo("#content");

This will fire before the content is loaded, appending a blank html string to the document. The trick is understanding that the AJAX requests, and this second appension, are executed immediately, but the success function loading the results into the variable html does not fire until the server sends back the requested information.

My answer for how to fix this depends on what kind of condition is being checked in line 9. If it's something detectable via event listeners, I would rewrite success to do nothing but store the results in the global html variable, then write a second event listener that fires when your condition is met, appending the contents of html to your target and then clearing it. If, however, that condition cannot be detected with an event listener, I'd change your code to something like the following:

var html = "";
function loadByUrl(url) {
    $.ajax({
        url: url, 
        dataType: 'json',
        success: function(json) {
            $.each(json.data.children, function(i,item){
                html += "<div>" + item.data + "</div>";
                if( someCondition ) {
                    $(html).appendTo("#content");
                }
            });
        });
}

loadByUrl("http://fake1.com");
loadByUrl("http://fake2.com");
loadByUrl("http://fake3.com");

If you want to be able to force it to append after you've finished loading fake3.com, use closure to do something like:

var html = "";
function successFunction(force)
{
    return function(json) {
        $.each(json.data.children, function(i,item)
        {
            html += "<div>" + item.data + "</div>";
            if (force || someCondition)
            {
                $(html).appendTo("#content");
            }
        });
    };
}
function loadByUrl(url,force) {
    $.ajax({
        url: url, 
        dataType: 'json',
        success: successFunction(force)});
}

loadByUrl("http://fake1.com",false);
loadByUrl("http://fake2.com",false);
loadByUrl("http://fake3.com",true); // true => force appension.

Upvotes: 0

Related Questions