3

I have the following function:

  getTasks: function()
    {
        var taskRequest = Titanium.Network.createHTTPClient();
        var api_url = 'http://myawesomeapi.heroku.com/users/' + Ti.App.Properties.getString("userID") + '/tasks';

        var tasks = [];
        taskRequest.onload = function() {
            var response = JSON.parse(this.responseText), 
            len = response.length,
            i = 0,
            t;

            for(; i < len; i++)
            {
                task = response[i];
                var newTask = {};
                newTask.rowID = i;
                newTask.title = task.title;
                newTask.description = task.description;
                newTask.id = task.id;
                newTask.hasChild = true;

                tasks.push(newTask);
            }

            alert(tasks);
        }

        taskRequest.open('GET', api_url, false);
        taskRequest.setRequestHeader('Content-Type', 'application/json');
        taskRequest.send();

        alert(tasks);
            // return tasks;
    }

This function is in my controller; I call it in my view when I need to load the data in. However, I wish to return this data so I can assign it to a variable in the view.

Now what happens is that it returns emptiness. The last alert (bottom one) seems to be running too fast and it returns an empty array, while the one that only gets alerted after the onload function is done, contains what I need.

Now my obvious question, how can I get my function to return the array with the data, instead of without?

Putting a timer on it seems hardly the right decision.. Thanks!

Joris Ooms
  • 11,880
  • 17
  • 67
  • 124

2 Answers2

2

"However, I wish to return this data so I can assign it to a variable in the view."

Aside from making the AJAX request synchronous (which you probably don't want), there isn't any way to return the data.

Whatever code relies on the response needs to be called from within the response handler.

Since functions can be passed around, you could have your getTasks method receive a callback function that is invoked and will receive the tasks Array.

  getTasks: function( callback ) // receive a callback function
    {
        var taskRequest = Titanium.Network.createHTTPClient();
        var api_url = 'http://myawesomeapi.heroku.com/users/' + Ti.App.Properties.getString("userID") + '/tasks';

        taskRequest.onload = function() {

            var tasks = [];

            // code populating the tasks array

            alert(tasks);

            callback( tasks ); // invoke the callback
        }

        taskRequest.open('GET', api_url, false);
        taskRequest.setRequestHeader('Content-Type', 'application/json');
        taskRequest.send();
    }

So you'd use it like this...

myObj.getTasks(function(tasks) {
    alert('in the callback');
    alert(tasks);
      // Any and all code that relies on the response must be
      //   placed (or invoked from) inside here
    some_other_function();
});

function some_other_function() {

    // Some more logic that can't run until the tasks have been received.
    // You could pass the tasks to this function if needed.

}
  • Hey, thanks for the great reply and the example code. I tried that now and it works with the alerts; however, I think I get the same problem again when assigning it to a variable. I do this: `var data = this.controller.getTasks(function(tasks) { alert(tasks); return (tasks); }); alert(data);` but the alert seems to come before the data is received, so it returns empty again. Do I need another callback here? ;D – Joris Ooms Jan 29 '12 at 20:58
  • @cabaret: No, you simply won't be able to return the value. The `getTasks` function will return long before the response is received. What you need to do is put any code that relies on the response inside the callback function you're passing to `getTasks`. If that's a lot of code, you can break that other code into separate functions, as long as those functions *are called from within the callback*. –  Jan 29 '12 at 21:00
  • Oh, okay. I understand now! It's not a lot of code, so that should be okay. Thanks a lot for your help! – Joris Ooms Jan 29 '12 at 21:02
0

You are getting empty alert because when the bottom alert is executed the server response is not available and tasks array is empty.

When the server response comes the tasks array is populated by the code which you have in the onload handler so you see the tasks in the second alert.

ShankarSangoli
  • 69,612
  • 13
  • 93
  • 124
  • I know. Is there a way to make it wait or something so it returns the data I want? :/ – Joris Ooms Jan 29 '12 at 20:50
  • I think Titanium no more supports sync request. May be this link would help you http://developer.appcelerator.com/question/129776/titaniumnetworkcreatehttpclient-open-method-des-not-support-synchronous-calls-anymore. – ShankarSangoli Jan 29 '12 at 20:54