views:

32

answers:

1

I'm using a function which utilizes jQuery in order to grab information from a JSON feed. The problem here is that from the feed I must pick 10 items that meet the criteria of being within the last year (31 billion milliseconds from the request for argument's sake) and I have to specify how many results I want from the feed with a variable 'maxRows' that is inserted into the URL. Here's the function...

function topTen(rows) {
    $.getJSON("http://ws.geonames.org/earthquakesJSON?north=90&south=-90&east=-180&west=180&maxRows=" + rows, 
        function(json) {
            var topTen = new Array();
            var now = new Date();
            var i;
            for(i = 0; i < json.earthquakes.length; i++)
            {
                var time = json.earthquakes[i].datetime;
                var then = new Date(time.replace(" ", "T"));
                if(now - then < 31536000000) { topTen.push(json.earthquakes[i].eqid); }
            }
            if(topTen.length >= 10)
            {
                var html = "The Top Ten Earthquakes Of The Past Year<ol>";
                for(i = 1; i <= 10; i++)
                {
                    html += "<li id='number" + i + "' >" + topTen[i - 1] + "</li>";
                }
                html += "</ol>";
                $('#top_ten').html(html);
            }
        });
}

Now the problem is that from the first request it is likely I will not get 10 results that meet my criteria. So in order to counteract this I try to put the function in a loop until another criteria is met. However, this always winds up failing because the getJSON function (or perhaps the callback) is asynchronous, meaning if I try something like

    var rows = 10;
    do{
        topTen(rows);
        rows += 10;
    while(!document.getElementById("number10"))

The problem then becomes, however, that the function doing the actual work is not bound by the line-by-line timing of the loop and so the loop itself runs many, many, MANY times before any of the functions actually finish and the loop condition is met. So right now I'm trying to devise another approach that goes something like this

    topTen(rows);
    rows += 10;
    pause(1000);
    topTen(rows);
    rows += 10;
    pause(1000);
    topTen(rows);
    rows += 10;
    pause(1000);
    if(document.getElementById("number10"))
        alert("There's 10!");
    else
        alert("There's not 10!");

The pause is basically just what it sounds like and takes in milliseconds. A simple comparison of an initial date object to later date objects in a loop that I copied and pasted. This works to keep the functions from firing off immediately after one another, but then the problem becomes that the if condition is NEVER met. I don't know what it is, but no matter how much time I allow for pausing, the getElementById function never seems to find the element with an id of 'number10' even though I can see it very clearly in Firebug.

I've have been crashing my browser SEVERAL times because of this problem and I am seriously getting PO'd and sick of it. If anyone could find a solution to this problem or even suggest an easier, more elegant solution, I would be eternally grateful.

PS - I've tried things like global variables and using recursion to call topTen() from inside the callback function and send in a larger 'rows' variable, but those don't work because it seems like the callback functions are in their own contained little world where 90% of the rest of my javascript doesn't exist.

+1  A: 

You are doing this the wrong way...

You need to wait for one call to return before calling again. Lucky for you, you already have a function being called with it returns. So a simple change to that function and you are done.

var topTenList = new Array();


function topTen(rows) {
    $.getJSON("http://ws.geonames.org/earthquakesJSON?north=90&amp;south=-90&amp;east=-180&amp;west=180&amp;maxRows=" + rows, 
        function(json) {
            var now = new Date();
            var i;
            for(i = 0; i < json.earthquakes.length; i++)
            {
                var time = json.earthquakes[i].datetime;
                var then = new Date(time.replace(" ", "T"));
                if(now - then < 31536000000) { topTenList.push(json.earthquakes[i].eqid); }
            }
            if (topTenList.length < 10)
            {
               topTen(rows+10);
               return;
            }
            else
            {
                var html = "The Top Ten Earthquakes Of The Past Year<ol>";
                for(i = 1; i <= 10; i++)
                {
                    html += "<li id='number" + i + "' >" + topTenList[i - 1] + "</li>";
                }
                html += "</ol>";
                $('#top_ten').html(html);
            }
        });
}
Hogan
Um... I don't think I understand.
Mathias Schnell
Mathias: Added the code
Hogan
I tried that. It doesn't work. The error in Firebug says that the function topTen() does not exist.
Mathias Schnell
Rather, it says that topTen(rows + 10); is not a function.
Mathias Schnell
try the change above.
Hogan
yes topTen was the name of the function and the local variable, I made the array a different name... see if that works.
Hogan
Wow. It worked! All I had to do was change the function's name! I guess it was confusing topTen the function with topTen the array. I was under the impression the interpreter would be able to tell the difference, but I guess it's not quite as smart as I thought. Or maybe I'm not as smart as I thought. Well, either way, IT WORKED! Thank you so much, you've just saved me SO many headaches.
Mathias Schnell
also notes, you will have to clear the array before you call the function if you call it more than once. A global variable is not great, you could pass it as a parameter too. That would be better.
Hogan
grats... good luck with the project. Please accept the answer and give it a vote up.
Hogan
I did it without the use of a global array. That simple function name change was all I needed. I assume that's the better method if I don't need to keep the array or any of its data after I've printed it.
Mathias Schnell