Thursday, September 1, 2016

SharePoint JSOM : Alternative approach to nested executeQueryAsync with loops

Let’s assume that we need to get all pages in a site. Following are the steps we have to perform

  • Get all libraries
  • Get items in each library

Traditionally we would write a code like the below, but it will not provide expected response. This is due to the asynchronous nature of operations

Code that does not work

var context = SP.ClientContext.get_current();
var hostContext = new SP.AppContextSite(context, decodeURIComponent(getQueryStringParameter("SPHostUrl")));

var web = hostContext.get_web();
var lists = web.get_lists();
context.load(lists);

context.executeQueryAsync(
function () {
    var listEnumerator = lists.getEnumerator();
    while (listEnumerator.moveNext()) {
        var oList = listEnumerator.get_current();
        if (oList.get_baseType() === 1) {

            var camlQuery = new SP.CamlQuery();
            var items = list.getItems(camlQuery);
            context.load(items);
            context.executeQueryAsync(
                function () {
                    var listEnumerator = lists.getEnumerator();

                }, function (sender, args) {
                    console.log('error!');
                });
        }
    }
}, function (sender, args) {
    console.log('error!');
});

As the solution, I broke the functionality in to two methods using Deferred objects. I’ve written a blogpost on Deferred objects and you can find it from here. Following is the preferred approach.

Working code with Deferred objects

function getSitePages()
{
    var context = SP.ClientContext.get_current();
    var hostContext = new SP.AppContextSite(context, decodeURIComponent(getQueryStringParameter("SPHostUrl")));

    var web = hostContext.get_web();
    var lists = web.get_lists();
    context.load(lists);

    context.executeQueryAsync(
    function () {
        var listEnumerator = lists.getEnumerator();
        while (listEnumerator.moveNext()) {
            var oList = listEnumerator.get_current();
            if (oList.get_baseType() === 1) {

                var promise = getListItems(oList).then(function (state) {
                    console.log(state);
                });

            }

        }
    }, function (sender, args) {
        console.log('error!');
    });
}

function getListItems(list) {
    var dfd = $.Deferred();

    var context = SP.ClientContext.get_current();
    var hostContext = new SP.AppContextSite(context, decodeURIComponent(getQueryStringParameter("SPHostUrl")));
           
    var camlQuery = new SP.CamlQuery();
    camlQuery.ViewFields = "<FieldRef Name='FileExtension' /><FieldRef Name='Title' />";
    camlQuery.set_viewXml("<View><Query><Where><Or><Contains><FieldRef Name='FileLeafRef' /><Value Type='Text'>.aspx</Value></Contains><Contains><FieldRef Name='FileLeafRef' /><Value Type='Text'>.html</Value></Contains></Or></Where></Query></View>");
    var items = list.getItems(camlQuery);
    context.load(items);

    context.executeQueryAsync(
        function () {
            var itemsCount = items.get_count();
            if (itemsCount > 0) {
                obj = {};
                obj.ListName = list.get_title();
                obj.ListPages = [];

                for (var i = 0; i < itemsCount; i++) {
                    var item = items.itemAt(i);
                    obj.ListPages.push(item.get_item('FileRef'));
                }

                dfd.resolve(obj);
            }
                   
        }, function (sender, args) {
            dfd.reject(sender, args, errorMsg);
        });

    return dfd.promise();
}

No comments: