1

I have used (in a for loop):

var itm = mylist.getItemById(id);

I tried using context.executeQueryAsync , but I read that I can't use this to store or return global variables. The only examples I see are those which use async, but then I also see the comments saying how "useless" it is outside of alerts. Is there not a way to get around this?

edit:

function doSomething() {

//example from below
var idArray = new Array();
idArray[0] = 26;
idArray[1] = 30;
var itm = new Array();
var globalTitle = new Array();
for(var ii in idArray) {
  itm.push(list.getItemById(idArray[ii]));
  ctx.load(itm[ii]);
  ctx.executeQueryAsync(onSuccess, onFail);
  function onSuccess() { 
    globalTitle.push(itm[ii].get_item('FileLeafRef'));
  }
  function onFail() {alert('fail');}
}
alert(globalTitle.toString());
}

The main issue is that globalTitle does not receive a value outside of "executeQueryAsync." I can alert inside that (just after pushing the file names to it), but the alert at the bottom should not appear blank.

  • You need to post some code so that we can see what is going on. This is not enough to go on. But as mike.fisher points out your question/comments don't make a lot of sense. We have no idea what globalTitleis or how you are assigning to it. – Robert Kaucher Mar 10 '14 at 23:34
  • Sorry, I'm honestly not sure what you're suggesting. The only lines I have removed from this function are the definitions of ctx,listid,web, etc. but those are all fine as I use them in many other methods in this same file. All I'm trying to say is that if you copy the example verbatim, it globalTitle does not actually receive the values I am "pushing" to it. The answer at the bottom here: sharepoint.stackexchange.com/questions/24869/… might better explain what I'm trying to say. Sorry I am very unclear. – Dinerdo Mar 10 '14 at 23:37
  • Your code was not there when I posted. – Robert Kaucher Mar 10 '14 at 23:39
  • Now I'll give you an upvote. – Robert Kaucher Mar 11 '14 at 1:08
4

Your issue is in understanding the async nature of JavaScript.

The reason why there are no values is because you are attempting to access it before the executeQueryAsync function has returned and done it's job.

Any logic that needs to access the values in globalTitle needs to be abstracted into a function or functions that can be invoked inside of the success callback in executeQueryAsync. But that only works for one call.

  var globalTitle = [];
  context.executeQueryAsync(onSuccess, onFail);
  function onSuccess() { 
    globalTitle.push(itm[ii].get_item('Title'));
    businessLogic();
  }
  function onFail(sender, args) {
     alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
  });

  function businessLogic(){
     //Do stuff in here. with globalTitle
  }

But if you wanted to make it more modular and work with multiple calls you should look at using some patters to manage the async flow of data better. A simple option would be to have an integer index like

var numberOfcallsReturned = 0;

Then in the success callback you would increment that number and check in against idArray.length to see if all of the executions have returned;

    numberOfcallsReturned++;
    if(numberOfCalls = idArray.length){ 
       businessLogin();
    }

These might be good resources for you here since you have multiple queries.

https://stackoverflow.com/questions/6659489/design-pattern-for-managing-multiple-asynchronous-javascript-operations http://blog.kevinchisholm.com/javascript/jquery/using-jquery-deferred-to-manage-multiple-ajax-calls/

Personally, I would use ListData.svc to do this sort of operation along with jQuery. I think the JSOM is overly verbose for things like this. In this case TestList is the list name. Notice that in the SharePoint UI it is Test List but ListData.svc removes the spaces.

Here is an example using jQuery and ListData.svc

var globalTitles = [];
var idArray = [];
idArray[0] = 4;
idArray[1] = 3;
var requests = [];

var getItemById = function(id){
    var url = "https://mysharepoint.com/_vti_bin/ListData.svc/TestList(" + id + ")";
    return $.ajax({
            type: 'GET',
            url: url,
            dataType: 'json',
            success: function(data){ 
                globalTitles.push(data.d.Title);
            }
        });
}
for(var i = 0; i < idArray.length; i++){ 
    requests.push( getItemById(idArray[i]) );
}
$.when.apply($, requests).done(function(){ 
    console.log("Done");
    console.log(globalTitles.length); //Do stuff with the data here.
});

I personally feel this is easier to read and understand.

  • 1
    I wish I could give this answer more than one upvote. The basic problem is indeed understanding of how asynchronous programming works. And +1 for suggesting ListData.svc which is much better suited for such a simple task. – Louis Mar 11 '14 at 2:34
  • 1
    I would also suggest to look into Promises/Deferred objects, which make this kind of code somewhat clearer to read. – Louis Mar 11 '14 at 2:34
0

I hate to pose a question in an answer, but I don't have enough cool points to comment. There isn't really enough information here for me to fully understand what you're trying to do. If you're trying to load the value of a field for an item which you have the id of (over and over again for different items if you're doing this in a for loop?), then you need to get that item based on the id, executeQueryAsync and nested in the success use get_item('yourField'); to return the value of that field for that item. If that helps great, if not then more information in your question would help me respond more completely. Here is an example, really quickly (maybe not the greatest but should get the idea across):

var idArray = new Array();
idArray[0] = 1;
idArray[1] = 2;
var itm = new Array();
var globalTitle = new Array();
for(var ii in idArray) {
  itm.push(mylist.getItemById(yourArray[ii]));
  context.load(itm[ii]);
  context.executeQueryAsync(onSuccess, onFail);
  function onSuccess() { 
    globalTitle.push(itm[ii].get_item('Title'));
  }
  function onFail() {alert('fail');}
}
  • I have a function which takes the selected items and stores them into an array, and a separate array which stores those IDs (using getItemById). After using those IDs to get the file name (FileLeafRef) for each item, I want to pass those names into another function. I can pass the id array and the item array into the other functions, but when I use executeQueryAsync.. nothing seems to have changed in the global variable. – Dinerdo Mar 10 '14 at 23:08
  • Honestly that makes no sense to me. If you post your code I'll take a look at it for you, but that description alone doesn't make sense to me. This looks like you have an array of item objects in which case you wouldn't need to use getItemById because you already have that item in the first array. – mike.fisher Mar 10 '14 at 23:26
  • edit: Tried your code and the same issue arises :( Even within that same function, "globalTitle" returns blank or null values if I enter "alert(globalTitle.toString() just below that last bracket (again, still in the same function but outside of executeQueryAsync edit: I have uploaded the code – Dinerdo Mar 10 '14 at 23:27
  • Where are you getting the ids from? – mike.fisher Mar 10 '14 at 23:29
  • in my code, I am using the selectedIDs, but even if I try your example or others I have found (exactly as they are worded), the "globalTitles" will not appear in an alert for me unless I place them in the exectueQueryAsync. But I have a lot of functions I need to use the variable for and can't (or at least would much prefer to avoid) place all of them inside there. – Dinerdo Mar 10 '14 at 23:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.