Titanium Community Questions & Answer Archive

We felt that 6+ years of knowledge should not die so this is the Titanium Community Questions & Answer Archive

change variable outside of xhr.onload function

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.

— asked April 4th 2011 by Josey Morton
  • iphone
  • namespace
  • xhr.onload
0 Comments

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 April 4th 2011 by K T
    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 April 4th 2011 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 April 4th 2011 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');
    
    — answered April 5th 2011 by Tim Poulsen
    permalink
    0 Comments
The ownership of individual contributions to this community generated content is retained by the authors of their contributions.
All trademarks remain the property of the respective owner.