change variable outside of xhr.onload function

You must Login before you can answer or comment on any questions.

Greetings,

I'm creating my own namespace api for an app i'm building but i've run into one specific annoyance.

I created a function to handle logins, here is a simplified version of my code:

var myNS = {};
myNS.user = {};
 
myNS.user.createSession = function( _args ){
    var authorized;
 
    var request = Titanium.Network.createHTTPClient();
    request.onload = function(){
 
        // JSON encoded server return
        var response = this.responseText;
        var json = JSON.parse(response);
 
        if(json.status == 'success'){
            // Update authorized variable to true
            authorized = true;
        } else {
            authorized = false;
        }
 
    }
 
    // Open and send xhr request
    request.open(// standard open type and url);
    request.send();
 
    // Supposed to return __true__ or __false__ based on declaration given in .onload
    return authorized;
 
};
I'm sure you can tell but what I'm wanting to do is update the authorized variable declared at the beginning of the function based on the json return on the requests onload return.

Unfortunately when I test this it always logs as blank ('').

If I give it a value to begin with such as false then it always return false so it just isn't getting updated from within onload.

2 Answers

Accepted Answer

An async request will continue immediately after send() to your return statement, so return authorized will return whatever it's set to initially. Your onload handler will get called long after the function has returned.

What you'll need to do is provide a callback that can be called in your onload (or onerror) handler to alert your app to the status of the request.

In theory a synchronous request is possible, but if I remember right, at least one of iPhone or Android doesn't support it (properly, at least). It's good practice not to block on a network request, anyway, since you have no idea how long it will take and your app/UI will be completely unresponsive in the interim.

— answered 2 years ago by K T
answer permalink
2 Comments
  • good suggestion, I just tried that but its having the same effect.

    request.onload = function(){
        callback(this.responseText); 
    }
     
    function callback(response){
        // JSON encoded server return
        var json = JSON.parse(response);
     
        if(json.status == 'success'){
            // Update authorized variable to true
            authorized = true;
        } else {
            authorized = false;
        }
    }
    If I misunderstood please clarify.

    Thanks!

    — commented 2 years ago by Josey Morton

  • A little, maybe.

    I assume what you had originally was something like:

    function myAuthorizationFunction()
    {
        ...
        result = myNS.user.createSession(...);
        // Now handle result appropriately
        ...
    }
    The problem as pointed out is that you have no idea when the async request will return from the wilds of the internet; it shoots off the request.send() and your program continues on its merry way without pausing.

    What you need to do is move the logic for handling the authorization result into a callback function, so instead of a linear myAuthorizationFunction, you have something more like:

    function onAuthorizationResult(result)
    {
        // Now handle result appropriately
        ...
    }
     
    function myAuthorizationFunction()
    {
        ...
        myNS.user.createSession(..., onAuthorizationResult);  // extra callback argument
    }
    Then you'll have:
    myNS.user.createSession = function(..., onResult)
    and your request.onload will contain something like:
    if(json.status == 'success'){
        // Update authorized variable to true
        authorized = true;
    } else {
        authorized = false;
    }
    onResult(authorized);  // to actually tell the application about the authorization

    — commented 2 years ago by K T

As written, your authorized variable is available only within the createSession function. You could use something like the following so that it's available elsewhere in the namespace:

var myNS = {};
myNS.user = {};
 
myNS.user.createSession = function( _args ){
    myNS.authorized = false;
    // rest of your code
However, KT's code and suggestion also applies. Because the network operation is async, you'll need to either call a function as shown or fire an event that your app can listen for and react to.
Ti.App.fireEvent('user_authorized');
// or Ti.App.fireEvent('user_not_authorized');

Your Answer

Think you can help? Login to answer this question!