Skip to main content
4 of 5
added 360 characters in body

How to get multiple lists on a page using context.executeQueryAsync?

Code that I can execute like this is my end fantasy:

var listCollection1 = getList("listName1");
var listCollection2 = getList("listName2");
// at this line I now have both of those populated

Where getList is just a function in a different file and I don't need to use globals and can get different lists on different pages and multiple lists.

My problem ultimately is the asynchronous query. I'm not used to async so let me know if my thinking is mistaken. Initially I was doing something like this:

var listCollection1;
getList("listName1");

function doSomething(){
    // at this line I now have listCollection1 populated
}

function getList(listName) {

    var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
    var currentcontext = new SP.ClientContext.get_current();
    var hostcontext = new SP.AppContextSite(currentcontext, hostUrl);

    var web = hostcontext.get_web(); // hostcontext instead of currentcontext
    var lists = web.get_lists();
    var list = lists.getByTitle(listName);
    var listItemCollection = list.getItems(""); // use CAML query for specific requests
    
    hostcontext.load(listItemCollection);
    hostcontext.executeQueryAsync(

        function () {
             alert("got my list now, let's do something");
             listCollection1 = listItemCollection;
             // or just pass it directly
             doSomething(listItemCollection);
        }, 

        function () {
             alert("didn't get my list");
        }
    );
}

But with this method, I can't load multiple lists without a bunch of if statements or different functions.

I also find the whole "go to this function" if it executes correctly "go to this function" if it doesn't style of programming difficult to follow and excessive global variables frustrating to deal with.

I found this question titled How to return a value using context.executeQueryAsync?, which outlines a callback method. But when I implemented that, it didn't really solve anything for me. I still couldn't seem to return the value from anywhere or get it to act synchronously.

And tried to do a callback thing to see if it got me any closer to what I was hoping for:

function getList(listName) {

    var get = function (callback) {

        var hostUrl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));

        var currentcontext = new SP.ClientContext.get_current();
        var hostcontext = new SP.AppContextSite(currentcontext, hostUrl);
        var web = hostcontext.get_web(); // hostcontext instead of currentcontext

        var lists = web.get_lists();
        var list = lists.getByTitle(listName);

        listItemCollection = list.getItems(""); // use CAML query for specific requests

        currentcontext.load(listItemCollection);

        currentcontext.executeQueryAsync(function () {
            alert("asyn query successful");
            callback(null, listItemCollection);

        }, function (a, b) {
            alert("asyn query unsuccessful!")
            callback(new Error(b.get_message()));
        });
    };

    get(function (error, listItemCollection) {
        if (error) {
            alert(console.error(error));
            return;
        }

        console.log(listItemCollection); // it is here. I want to return it or send it somewhere from here
        return listItemCollection;
    });
}

But predictably it returns undefined and I'm in the same situation where I need to call another function to get out. Doesn't seem any different from the first method.

Alternatives or suggestions on how I can get something like what I have up top would be great. And if it's just not possible, thanks anyway.

Edit:

One thing that I've decided sort of works. Is passing a function as a parameter to getList that you want it to go to when successful. That way you can call

 getList("list1", functionForList1)
 getList("list2", functionForList2)

 function functionforList1(list){
    // do stuff
 }

 function functionforList2(list){
    // do *other* stuff
 }

function getList(listName, goToFunction) {

    var get = function (callback) {

        // blahblahblah

        currentcontext.executeQueryAsync(function () {
            callback(null, listItemCollection);

        }, function (a, b) {
            callback(new Error(b.get_message()));
        });
    };

    get(function (error, listItemCollection) {
        if (error) {
            alert(console.error(error));
            return;
        }

        goToFunction(listItemCollection);
    });
}     

Essentially now I can do:

    $(document).ready(function () {
        getList("mySPList", sharePointReady);
    });

    function sharePointReady(list) {
       // carry on having sorta asynchronously loaded it
       // and now I can use one function for each page
       // without like 5 global variables
    }