7

I'm attempting to loop through an ajax call for 3 different json files with the same naming convention and structure (but with slightly different data). I have been using deferred objects instead of the success option ever since I read a response by Alnitak in the forum (jQuery ajax success callback function definition) so that my ajax handling and callback handling could be decoupled. Below is my code:

<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=ISO-8859-1" />

<title>Stuff</title>
<script src="jquery-1.9.1.min.js" type="text/javascript"></script> 
</head>

<body>
<script Language="JavaScript">

    var myData = [];
    var myURL =  ["ticker1.json","ticker2.json","ticker3.json"];    //New Array for my URLs

    function getData(m) {

        return $.ajax({
            url : myURL[m],  //<<<---Want to loop through this array
            type : 'GET',
            dataType: 'json'
        });

    }

    function handleData(data){

        for (var i=0; i<data.test.msgOne.length; i++){
            myData[i] = data.test.msgOne[i];
        }

    };



    for (var j=0; j<3; j++){

        console.log(j);  //<<---First console statement
        var ajaxCall = getData(j).done(handleData);

        $.when(ajaxCall).done(function(){ //wait until the ajax call is done before writing

            console.log(j);  //<<---Second console statement

            for (var k=0; k<3; k++){
                document.write(myData[k])
                document.write('<br><br>');
            }

        });

    }

</script>
</body>
</html>

My code consists of an function called getData which performs an ajax call, then a function called handleData which simply loops through data in the json file from the ajax call and stores the data in an array myData. Then a for-loop attempts to output the data for the array myData to the screen. However, the problem is I am only getting the data from the first json file output on the screen, instead of all three sequentially.

So what I did was input two console.log statements in the for-loop: one before the ajax call and one after the ajax call gets done. The first console.log outputs 0,1,2 sequentially as expected, and the second gives a 3, which is unexpected. So then I assumed that the ajax calls weren't returning before the counter finishes. I replaced the for-loop with some logic statements and a while-loop (yes, I know the dangers of code running indefinitely) given below:

    var j=0;
    var whileFlag= new Boolean(1);
    var ajaxFlag = new Boolean(1);

    while (whileFlag) {

        if (ajaxFlag > 0) {
            ajaxFlag = 0;
            console.log(j);
            var ajaxCall = getData(j).done(handleData);
        }
        $.when(ajaxCall).done(function(){
            console.log(j);
            for (var k=0; k<3; k++){
                document.write(myData[k])
                document.write('<br><br>');
            }
            ajaxFlag = 1;
            j++;
        });

        if (j>=3) {whileFlag = 0};
    }

The replacement code was an attempt to force the ajax calls to finish and then execute code before moving onto the next ajax call. Well, the end result was a frozen browser, which was no bueno. Does anyone know how I might be able to go about writing the myData array for each of my json files to the screen? Any help and constructive comments are appreciated. Also, I need to keep the ajax call asynchronous since I will be working with jsonp datatypes in the future.

Additional question: I believe the browser hang up is due to ajax not returning the call, but the questions is why? If I choose not to implement the for-loop in the first example, and instead just set the j variable explicitly to 0, or 1, or 2, the data prints-out fine for the chosen json file, but If I do more than that it will only print the set of data from the first json file. It's like it's not possible to do multiple ajax calls or something. Any insight and help is appreciated. Thanks.

Community
  • 1
  • 1
ADT
  • 139
  • 1
  • 10

3 Answers3

2

The problem is your while loop is equivalent to...

 while (whileFlag) {

    if (ajaxFlag > 0) {
        ajaxFlag = 0;
        console.log(j);
        var ajaxCall = getData(j).done(handleData);
    }
    // Some thrid party (asynch Handler) changes j
    if (j>=3) {whileFlag = 0};
}

so ideally till Ajax completes your code runs as

 while (whileFlag) {
  if (j>=3) {whileFlag = 0};
    }

which hangs your browser...

If you want to really wait for 2nd Ajax call till 1st completes and so on..

 function getData(m) {

    return $.ajax({
        url : myURL[m],  //<<<---Want to loop through this array
        type : 'GET',
        dataType: 'json',
        myJ: m
    });

    }


 function handleData(data){

    for (var i=0; i<data.test.msgOne.length; i++){
        myData[i] = data.test.msgOne[i];
    }

    for (var k=0; k<3; k++){
            document.write(myData[k])
            document.write('<br><br>');
    }
    if(this.myJ<2){
    var myJ=this.myJ;
       setTimeout(function(){
           getData((myJ+1)).done(handleData).fail(failed);
           }, 100);
    }
};



 getData(0).done(handleData);

function failed(jqXHR, textStatus, errorThrown){
 alert("textStatus="+textStatus);
alert("Error= "+errorThrown);
}

As per comment with alert if its working then use settimeout.. and it will work

rahul maindargi
  • 5,359
  • 2
  • 16
  • 23
  • Thanks for the help. However, it appears that I'm not getting the final result I am wanting. It is only printing out the first json file results. – ADT May 16 '13 at 17:30
  • check `alert(this.myJ)` before `if(this.myJ<2){` if its undefined then try $(this).myJ... Have you notice change in ajax call? `myJ: m` thats the key – rahul maindargi May 16 '13 at 19:39
  • The alert(this.mJ) gives : 0, which is correct, however, the code you have presented only will printout the desired data from the first json file. If I add getData(1).done(handleData); at the end of the code, it still will only print the data from the first json file and not the second I have also specified. What I really want is to be able to printout the data from all three json files in a row. For some reason, it keeps getting hung up on the first ajax call (from what I can tell). Any other ideas? – ADT May 16 '13 at 19:51
  • 1
    I will suggest `alert("here");` `alert(data.test.msgOne)` and `(data.test.msgOne[0])` in `function handleData(data){` first line... see if you are getting results for 2nd ajax request correctly... what you say can happen if first request sucessful and returned `json` like `data.test.msgOne` but 2nd one either failed... or did not returned the json in corect format like instead of `data.test.msgOne` returned `data.test.msgONE` then javascript will fail and you will see only 1 result in print – rahul maindargi May 17 '13 at 08:29
  • The alerts worked. I eventually just used one alert which was the alert(data.test.msgOne) statement and I put in a for-loop around the last statement of your code above: getData(i).done(handleData) (replaced the 0 with an index variable, i). When I do this without the alert(Data.test.msgOne statement), I only get the first set of json data to print, but if I include the alert, everything alerts correctly and is printed out to the screen! Which is great! But the question still remains, is there a way to get everything to output to the screen correctly without having the alert statements go off? – ADT May 17 '13 at 12:58
  • Another really strange thing is that the order of the alerts and printed data to the screen is from the 3rd json file to the 1st, instead of the other way around. The console is telling me though that the json files are being accessed in the correct order. Not sure why it's doing it that way. – ADT May 17 '13 at 13:04
  • The question still remains, is there a way to get everything to output to the screen in the correct order, without having the alert statements go off? – ADT May 17 '13 at 13:33
  • If you noticed i added Settimeout.. that should get you working... without alerts... have you tried that? – rahul maindargi May 17 '13 at 13:46
  • If I use your exact code given above with the modifications, it doesn't work. I only get the first json file printout to the screen. The console also says I only am accessing the first json file. I'm not sure if the if-statement near the end is doing the trick. – ADT May 17 '13 at 14:07
  • Same thing is going on. Not sure what it is. – ADT May 17 '13 at 15:29
  • which browser? anything specific? or all? – rahul maindargi May 17 '13 at 15:45
  • I am using firefox. Just data from the first json file. Nothing else. – ADT May 17 '13 at 15:49
  • See updated naswer.. and check if you get any error alert... Or use `getData((myJ+1)).always(handleData)` – rahul maindargi May 17 '13 at 15:51
  • So the failed function didn't even execute the alerts, so I'm assuming it didn't fail. I tried the second suggestion and I am still getting the first json file data printed only. – ADT May 17 '13 at 16:01
  • I have posted the json file contents in a new response below in case you want to check it for yourself. – ADT May 17 '13 at 16:18
  • There is nothing wrong in the above jscode for sure. it did solved your browser hang issue.. here is jsfiddle that code is working...`http://jsfiddle.net/hn4FH/1/` .. May be you need to show us your real code to help you better. as it solved the issues you mentioned in question, I will expect you to accept answer – rahul maindargi May 18 '13 at 18:50
0

If you know there are always three calls, you could do something like this:

function getData(url) {
    return $.ajax({
        url: url,
        //...
    });
}

function handleData(data1, data2, data3) {
    //display the data however you like
}

$(document).ready(function() { 

    var request1 = getData(myUrl[0]);
    var request2 = getData(myUrl[1]);
    var request3 = getData(myUrl[2]);

    $.when(request1, request2, request3)
        .done(function(result1, result2, result3) {
            alert(result1.test.msgOne[0]);
        });    

});

In this case, handleData() will only be called once, after all three calls have finished.

If you don't know how many results you'll have, you could iterate over the myUrl array and push the deferreds into an array. try this link for an example of passing an array of deferred objects to $.when().

Another edit

I've updated the original code. I think you're getting hung up on the deferred object. The deferred object (request1, for example) does not contain the response. When you call $.when(request1).done(function(result1) { }); the json result of request1 is passed into the function.

Community
  • 1
  • 1
Jason P
  • 26,984
  • 3
  • 31
  • 45
  • I'm not sure this is going to work as you have outlined it here. result1,2,3 are undefined. – ADT May 17 '13 at 15:46
  • Well, request1 isn't even coming up as defined either when I put an alert after it: alert("Request1 is: " + request1); which then produced "object Object" as it's value. – ADT May 17 '13 at 16:10
  • If you alert the value and get "Object object", then it is defined. Javascript objects just don't have a very helpful string output. – Jason P May 17 '13 at 16:12
  • My bad. Thanks. So how can I go about seeing what's in that object? I have tried accessing it as I would normally expect, but I am getting it's not defined. For example: request1.test.msgOne[1] isn't working. – ADT May 17 '13 at 16:17
  • Try using result1 instead of request1. – Jason P May 17 '13 at 16:26
  • Well I am using alert(request1.test.msgOne[0]); right after var request1=getData(myURL[0]); and getting the object Object return. If I use alert(result1.test.msgOne[0]); instead it is undefined. – ADT May 17 '13 at 16:39
0

Here are the three json files in case you want to test things yourself:

  • ticker1.json:

    { "test": { "msgOne": [ "ticker1 Remote One", "ticker1 Remote Two", "ticker1 Remote Three" ], "msgTwo": "Remote2", "msgThree": "Remote3" } }

  • ticker2.json:

    { "test": { "msgOne": [ "ticker2 Remote One", "ticker2 Remote Two", "ticker2 Remote Three" ], "msgTwo": "Remote2", "msgThree": "Remote3" } }

  • ticker3.json:

    { "test": { "msgOne": [ "ticker3 Remote One", "ticker3 Remote Two", "ticker3 Remote Three" ], "msgTwo": "Remote2", "msgThree": "Remote3" } }

ADT
  • 139
  • 1
  • 10