views:

467

answers:

5

I have a problem returning data back to the function I want it returned to. Code below:

function ioServer(request_data, callback)
{
    $.ajax({
        cache: false,
        data: "request=" + request_data,
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown){},
        success: function(response_data, textStatus){
      callback(response_data);
      },
        timeout: 5000,
        type: "POST",
        url: "/portal/index.php/async"
    });
}   

function processRequest(command, item, properties)
{
    var request = {};
    request.command = command;
    request.item = item;
    request.properties = properties;
    var toServer = JSON.stringify(request); 
    var id = ioServer(toServer, processResponse);
    return id;
}

function processResponse(fromServer)
{
    if (fromServer.response == 1)
    {
     return fromServer.id; 
    } 
}

I invoke this piece of code by calling the processRequest function inside another function. Sending the request and retrieving the response works just fine. However, I need to return a value 'id' from the response back to the processRequest function, so it in turn can return that value to its caller. As far as I can follow, the return in processResponse returns to $.ajax, but I need it to return further back to processRequest.

BTW the if statement in processResponse refers to a value set by the server-side PHP script to tell whether the request was allowed (for instance if the user was not logged in, fromServer.response would be 0). It does not have anything to do with the success/error routines of the $.ajax object.

Many thanks for the help.

@Jani: Thanks for the response, but could you clarify a bit more? The function where 'id' is needed has the following code:

$(#tabs).tabs('add', '#tab-' + id, 'New tab');

Are you saying I should try to execute this piece of code in the processResponse function? Because that is not what I intented to do; these function are meant to be an all-purpose solution to maintain state server-side. That is why I avoided placing this piece of code there.

+3  A: 

Since this is an asynchronous request, it does not directly return a value like that and it isn't possible.

The way to approach this is to have some method which performs any actions you need on the fetched data, instead of attempting to have a return value which will not work.

Jani Hartikainen
+3  A: 

I think maybe this is closer to what you are looking for...

function ioServer(request_data, callback)
{
    $.ajax({
        cache: false,
        data: "request=" + request_data,
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown){},
        success: function(response_data, textStatus){
                processResponse(response_data, callback);
                },
        timeout: 5000,
        type: "POST",
        url: "/portal/index.php/async"
    });
}   

function processRequest(command, item, properties, callback)
{
    var request = {};
    request.command = command;
    request.item = item;
    request.properties = properties;
    var toServer = JSON.stringify(request); 
    ioServer(toServer, callback);
}

//internal callback to handle response code
function processResponse(fromServer, callback)
{
    if (fromServer.response == 1)
    {
        //call the callback with the id
        callback(fromServer.id);   
    }   
    else
    {
        //You have to remember to call the callback no matter what
        //or the caller won't know when it's complete
        callback(null);  //or some other "didn't get a valid response" value
    } 
}
Tony Heupel
Added explanation for your code suggestion and how the calling code will look like. I hope you don't mind. http://stackoverflow.com/questions/1094716/how-does-one-return-data-to-the-original-caller-function-in-javascript/1095251#1095251
SolutionYogi
A: 

Instead of implementing blocking to simulate a synchronous call like someone else previously posted, just make the AJAX call itself synchronous and update your success wrapper:

function ioServer(request_data, callback) {
    var response = null;
    $.ajax({
        cache: false,
        data: "request=" + request_data,
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown){},
        success: function(response_data, textStatus) {
                response = callback(response_data);
        },
        timeout: 5000,
        type: "POST",
        url: "/portal/index.php/async",
        async: false
    });

    return response;
}

Edit: Although useful, this is sorta against the grain of "normal" AJAX use. I would suggest changing your approach instead.

Justin Johnson
You don't want to make synchronous call as it may freeze browser if ajax request could not be completed quickly.
SolutionYogi
@solutionyogi Hah, ya, I was in the process of making an edit about that when you commented. However, I've (begrudgingly) done this in the past with no browser-freezing issues. As far as I know, JavaScript just waits/blocks, and doesn't execute anything.
Justin Johnson
+2  A: 

As Tony didn't provide any comments, let me add details about what he is suggesting.

As you have learned, the processRequest function completes as soon as $.ajax call is made because $.ajax method is asynchronous. So how would you notify the caller of processRequest that the task is done?

Simple, you ask that the caller of processRequest to supply a 'callback function'. The processRequest will call this function whenever it has received the ajax output. In tony's code, this is the last argument to the processRequest function.

So your calling code will now look like

function tabMethod()
{
     processRequest('command', 'item', 'properties', 
                  function(id)
                  {
                     if(id == null) 
                     {
                          alert('There is a problem!');
                          return;
                     }
                     $('#tabs').tabs('add', '#tab-' + id, 'New tab');
                  });


};
SolutionYogi
Yes, thank you for the more explicit clarification of the use!
Tony Heupel
And a vote up for the awesome clarification...
Tony Heupel
A: 

Awesome! Thank you guys for the help, it works like a charm now. And I've learned to use callbacks better. Here's the full working code:

createTab('#tabs'); // I'm using JQuery UI to handle tabs    

function createTab(parent_element){
         var name = {};
         name.name = "New tab";
         var position = {};
            position.position = $(parent_element).tabs('length') + 1;
         var properties = new Array();
         properties[0] = name;
         properties[1] = position;
         processRequest(1, 1, properties, 
                      function(id)
                      {
                         if(id == null) 
                         {
                              alert('There is a problem!');
                              return;
                         }
                         $('#tabs').tabs('add', '#tab-' + id, 'New tab');
                      });
        }

function ioServer(request_data, callback)
{
    $.ajax({
        cache: false,
        data: "request=" + request_data,
        dataType: "json",
        error: function(XMLHttpRequest, textStatus, errorThrown){},
        success: function(response_data, textStatus){
                processResponse(response_data, callback);
                },
        timeout: 5000,
        type: "POST",
        url: "/portal/index.php/async"
    });
}   

function processRequest(command, item, properties, callback)
{
    var request = {};
    request.command = command;
    request.item = item;
    request.properties = properties;
    var toServer = JSON.stringify(request); 
    ioServer(toServer, callback);
}

//internal callback to handle response code
function processResponse(fromServer, callback)
{
    if (fromServer.response == 1)
    {
        //call the callback with the id
        callback(fromServer.id);   
    }   
    else
    {
        //You have to remember to call the callback no matter what
        //or the caller won't know when it's complete
        callback(null);  //or some other "didn't get a valid response" value
    } 
}

And it adds a new tab at the end of the list in the page. This is now also stored server-side with PHP and MySQL, just like I wanted it.

Thanks again!