Can't get correct return value from an jQuery Ajax call [duplicate]


This is supposed to return a JSON object containing a list of picture filenames. The commented alert shows the correct data, but alert(getPicsInFolder("testfolder")); shows "error".

function getPicsInFolder(folder) {
  return_data = "error";
  $.get("getpics.php?folder=" + folder, function (data) {
    data = jQuery.parseJSON(data);
    $.each(data, function (index, value) {
      data[index] = "folders/" + folder + "/" + value;
    });
    //alert(data); // This alert shows the correct data, but that's hardly helpful
    return_data = data;
  });
  return return_data;
}

What am I doing wrong?

You are calling the asynchronous $.get() method, where its callback function will be called after your getPicsInFolder() function returns. Follow the comments in the example below:

function getPicsInFolder(folder) {
   return_data = "error";
   // Since the $.get() method is using the asynchronous XMLHttpRequest, it 
   // will not block execution, and will return immediately after it is called,
   // without waiting for the server to respond.
   $.get("getpics.php", function (data) {
      // The code here will be executed only when the server returns
      // a response to the "getpics.php" request. This may happen several 
      // milliseconds after $.get() is called.
      return_data = data;
   });

   // This part will be reached before the server responds to the asynchronous
   // request above. Therefore the getPicsInFolder() function returns "error".
   return return_data;
}

You should consider refactoring your code in such a way that the logic to handle the JSON object is in the $.get() callback. Example:

$.get("getpics.php?folder=test", function (data) {
   // Handle your JSON data in here, or call a helper function that
   // can handle it:
   handleMyJSON(data); // your helper function
});

You're getting the data asynchronously. The callback function function (data) {} is called after getPicsInFolder returns.

You have two options:

  1. (the bad option): set your ajax call to be synchronous.

  2. (the right option): restructure your code, so that anything that needs to happen with the return data happens in the callback.

One way to do this would be to pass a callback into getPicsInFolder, like this:

function getPicsInFolder(folder, callback) {
    return_data = "error";
    $.get("getpics.php?folder=" + folder, function (data) {
        data = jQuery.parseJSON(data);
        $.each(data, function (index, value) {
            data[index] = "folders/" + folder + "/" + value;
        });
     callback(data); //pass data into the callback function
});

Then, when you call your getPicsInFolder, instead of doing:

pics = getPicsInFolder('foldername');
//do something with pics

do this:

getPicsInFolder('foldername', function (pics) {
    //do something with pics
});

AJAX requests should be asynchronous (you are able to do synchronous ones at the cost of halting execution and in effect blocking your UI).

getPicsInFolder() is returning before the AJAX request has completed. You need to update you UI/handle the JSON object returned on the complete event (the anonymous function you are passing as an argument to $.get()):

$.get("", function ()
{
    // This anonymous function will execute once the request has been completed

    // Update your UI/handle your data here
});

Say I wanted to update an element in my UI...

$("#ID-of-a-button-in-the-UI").click(function () // executes on click
{
    $.get("url-to-JSON-object", function (json) // executes on request complete
    {
        $("#ID-of-element-to-update").html(json.rows[0].key); // updates UI
    });
});

You're confused about how AJAX works. The data is not available until the request has completed, which happens after the function has returned. And the data is only available within the callback.