0

I know this is a Functions 101 type question, but we all need to learn sometime.

I have a AJAX call function (snippet below) stored in my own library .js file which returns a number of variables in an object.

function getMyDetails(){
//does processing

    return { 
        firstName: firstName,
        office: office, 
        manager: manager, 
        workphone: workphone, 
        isAdministrator: isAdministrator 
        }
   }

In the script on my webpage I am calling this function as follows:

$userDetails = getMyDetails();

and then attempting to refer to the items in the object as such:

$userFirstName = $userDetails.firstName;

but when running the script I am being returned with a "$userDetails is undefined" error in the console.

Q: How should I be referencing the getMyDetails() function to enable me to expose the returned variables in my page?

Update:

My full function code is here. In an attempt to abstract the problem, I didn't include it earlier as I'm working on a SharePoint site and making use of the SPServices library and so my AJAX call is wrapped up in a separate library function

function getMyDetails(){
var $userName = $().SPServices.SPGetCurrentUser({fieldName: "Name", debug: true });
    $().SPServices({
      operation: "GetUserProfileByName",
      async: false,
      AccountName: $userName,
      completefunc: function (xData, Status) {
        var firstName = getUPValue(xData.responseXML, "FirstName");
        var office = getUPValue(xData.responseXML, "Office");
        var manager = getUPValue(xData.responseXML, "Manager");
        var workphone = getUPValue(xData.responseXML, "WorkPhone");
        var SharepointAdministrator = getUPValue(xData.responseXML, "SharepointAdministrator");
        alert("What I've got is " + firstName +" and " + office +" and " +  manager +" and " + workphone  +" and " + SharepointAdministrator);

        return { 
            firstName: firstName,
            office: office, 
            manager: manager, 
            workphone: workphone, 
            SharepointAdministrator: SharepointAdministrator 
            }
       }
    });

    function getUPValue(x, p) {
      var thisValue = $(x).SPFilterNode("PropertyData").filter(function() {
        return $(this).find("Name").text() == p;
      }).find("Values").text();
      return thisValue;
    }
}

Whilst I acknowledge it is [generally] not good practice, I am making the AJAX call synchronously (with the 'async: false' option) and all variables are being populated correctly in my alert statement before any further down-stream processing [appears to] take place.

Fairfield
  • 115
  • 5
  • 1
    [Possible Duplicate](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call/16825593#16825593). Short answer - that's not how async requests work in JS. Long answer is in the link :) – Benjamin Gruenbaum Nov 01 '13 at 01:04
  • show more of the complete script, a copy and paste may reveal typos, and it helps the community get a better idea of dependencies and program flow, etc. – zamnuts Nov 01 '13 at 01:09
  • Thanks for all the feedback so far. I have edited the post to provide further code detail, although in doing so acknowledge this gives the question a definite SharePoint slant. – Fairfield Nov 01 '13 at 01:40

2 Answers2

2

You are making an ajax call, but you are not capturing the returned result!

There's more than one way to do it, try this:

function getMyDetails(){
var myDetails;
var $userName = $().SPServices.SPGetCurrentUser({fieldName: "Name", debug: true });
$().SPServices({
  operation: "GetUserProfileByName",
  async: false,
  AccountName: $userName,
  completefunc: function (xData, Status) {
    var firstName = getUPValue(xData.responseXML, "FirstName");
    var office = getUPValue(xData.responseXML, "Office");
    var manager = getUPValue(xData.responseXML, "Manager");
    var workphone = getUPValue(xData.responseXML, "WorkPhone");
    var SharepointAdministrator = getUPValue(xData.responseXML, "SharepointAdministrator");
    alert("What I've got is " + firstName +" and " + office +" and " +  manager +" and " + workphone  +" and " + SharepointAdministrator);

    myDetails = { 
        firstName: firstName,
        office: office, 
        manager: manager, 
        workphone: workphone, 
        SharepointAdministrator: SharepointAdministrator 
        };
   }
});

return myDetails;

function getUPValue(x, p) {
  var thisValue = $(x).SPFilterNode("PropertyData").filter(function() {
    return $(this).find("Name").text() == p;
  }).find("Values").text();
  return thisValue;
}
}
Christophe
  • 27,383
  • 28
  • 97
  • 140
1

If there's an asynchronous ajax function in this processing:

function getMyDetails(){
//does processing including async ajax calls

    return { 
        firstName: firstName,
        office: office, 
        manager: manager, 
        workphone: workphone, 
        isAdministrator: isAdministrator 
        }
   }

then, the issue is that the asychronous nature of the ajax call means that it doesn't finish until SOMETIME LATER. Thus you can't use normal sequential programming the way you are because the ajax call hasn't completed yet when getMyDetails() returns, thus all the data values are still undefined.

Instead, you have to change the flow of how your code works. You can't just create a function for getMyDetails() like you have. I don't know the overall structure of what you're trying to do, but you will probably need to put the logic that uses the result of the ajax call into a callback function that gets called when the ajax function is done.

That could look like this:

function getMyDetails(callback){
//does processing including ajax calls

   // inside the ajax success handler, put this:
   callback({ 
        firstName: firstName,
        office: office, 
        manager: manager, 
        workphone: workphone, 
        isAdministrator: isAdministrator 
        });
   }

Then, when you want to use this, you use it like this:

getMyDetails(function(data) {
    // code goes here that uses data.firstName, data.office, data.manager, etc...
});

Then, all code that uses the details must be placed into that callback function. You can't just do the normal sequential programming like you were in order to use asynchronous ajax calls.

Other related answers:

How to call an asychronous JavaScript function and block the original caller

How to get value from a javascript function which is using ajax

Undefined Indexes in Array after Asynchronous Requests

How do "recursive AJAX callbacks" in JavaScript work?

Why does my jQuery AJAX function always return false?

How to access variable inside a block

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979