Tuesday, December 24, 2013

Using the When...Done Pattern with Promises in SharePoint 2013 Apps

copyright form: www.shillier.com

I have written a couple of posts about using promises to control the sequential execution of asynchronous calls in SharePoint 2013. If you are new to promises, go back to the previous posts for more information. This post will assume you understand the basics.
Instead of sequential operations, what about when you need to control multiple parallel asynchronous calls? In this post, I’ll discuss the when…done pattern in SharePoint 2013 apps using REST. Specifically, I’ll examine a scenario where an app loads, creates 2 lists programmatically, and waits for both lists to be created before rendering the user interface. This type of scenario is useful when your app must execute several initialization operations before it is ready for use.
Let’s start with a library for creating a new SharePoint 2013 list using REST.
"use strict";
var WingtipToys = window.WingtipToys || {}WingtipToys.Rest = WingtipToys.Rest || {}
WingtipToys.Rest.Lists = function () {
     var create = function (title, description, template){        var deferred = $.ajax({            url: _spPageContextInfo.webServerRelativeUrl +                 "/_api/web/lists",            type: "POST",            contentType: "application/json;odata=verbose",            data: JSON.stringify(                {                    '__metadata': {                        'type''SP.List'                    },                    'Title': title,                    'Description': description,                    'BaseTemplate': template,                    'AllowContentTypes'true,                    'ContentTypesEnabled'true                }),            headers: {                "accept""application/json;odata=verbose",                "X-RequestDigest": $("#__REQUESTDIGEST").val()            }        });
         return deferred.promise()
    };
     return {        create: create    };
 }();
This library uses an HTTP POST operation to create the new list. Notice that the library uses the $.ajax() method to make the call. Also notice that the call returns a jQuery deferred object already so there is no need for us to create one separately. The create() function simply returns the promise() from the deferred. The built in support for deferred in jQuery makes it super easy to build REST libraries for your apps.
In past examples, I’ve used the then() method of the returned promise to execute sequential asynchronous calls. In this case, however, I will use the jQuery when() method to execute multiple asynchronous calls in parallel and thedone() method to show the app’s UI when all async calls have completed. Here’s the code:
$(document).ready(function () {
    //Hide the app's UI    $("#mainDiv").hide();    $("#loadingDiv").show();

    //Create 2 announcement lists with 2 items each
    $.when(
         //List1        WingtipToys.Rest.Lists.create(            "Announcements1",            "The first Announcements List",            SP.ListTemplateType.announcements),
         //List2        WingtipToys.Rest.Lists.create(            "Announcements2",            "The second Announcements List",            SP.ListTemplateType.announcements),
     ).done(
             function (x1, x2) {
                         //Show UI                        $("#mainDiv").show();                        $("#loadingDiv").hide();
             });
});
The first thing to notice is that the code is wrapped in the $(document).ready() method so that it starts execution as soon as the DOM is available. Next, notice that jQuery is used to hide the main part of the app UI and show a loading message to the user. This loading message will stay in place until both of the required lists are created.
The real excitement begins with the $.when() method. This method accepts any number of promises separated by commas. When all of the promises are resolved, the done() method fires. In our example, the two promises are the return values from separate calls to the create() function in the library. When both of these promises resolve, jQuery is used to display the app’s UI because it is now ready for the user.
Note that the completion function contained within the done() method has two parameters (x1 and x2). This function will have a return parameter for each promise, which can be used to retrieve the return data from the async operation. When coding this function, simply add additional parameters to the function so that the return parameters match one-to-one with the promises. You can then read information about the created lists from the parameters using code such as this:
var title1 = x1[0].d.Title;var title2 = x2[0].d.Title;var type1 = x1[0].d.ListItemEntityTypeFullName;var type2 = x2[0].d.ListItemEntityTypeFullName;
Take advantage of the when…done pattern whenever you need to execute multiple async calls in parallel and perform a function only after all of them are resolved successdfully.

No comments: