Geeks With Blogs
Thorvald Bøe
Ok, I will try not to make this a rant, but after knocking my head against the proverbial wall for several hours, that is going to be a tough one, LOL.

The problem was seemingly trivial: Create a SharePoint hosted add-in part with a button that creates an item in a list in the host web.

After all, I have been working with list items quite a bit from the SP hosted add-in, so doing it from an add-in part should not be so difficult, right? Wrong!

As you might know, when modifying a sharepoint list (e.g. by creating a list item) with REST, you need to supply a token that is called the form digest or request digest. If you are doing this from within the add-in, or from just a CEWP on a page (not an add-in), you can simply grab the form digest from a hidden variable on the page, like this:

$("#__REQUESTDIGEST").val()

Working with an add-in part is a different story. The add-in part runs inside an iframe on the regular page, but there is no form digest hidden variable. So I thought, I'll just grab it from the host page. And that is where my problems started.

I created a code snippet on the host page that grabbed the form digest, and sent it to the app part using iframe postMessage. To make a long story short, I had massive problems making it work, because of problems debugging it, and because I failed to see the significance of the targetOrigin parameter. But when I finally got it right, my update failed miserably, complaining about invalid form digest.

It turns out the form digest is produced from the url of the page where it resides, so using the host digest from within the app did not authenticate. So then I tried sending the host digest and the host url, but of course that was blocked by cross domain policy.

Finally I thought maybe there is another way to get the digest that is valid from within the app. And after some searching, I found it: You need to do a POST to /_api/contextinfo in order to get the valid digest. So I did this:

            $.ajax({
                url: appweburl + '/_api/contextinfo',
                method: "POST",
                headers: { "Accept": "application/json; odata=verbose" }
            }).done(function (data) {
                validRequestDigest = data.d.GetContextWebInformation.FormDigestValue;
            });

And then it worked!

I can't believe how much time I wasted chasing the wrong solution, but at least I am happy I did not give up and finally found the solution!

Hope this will help somebody else some day! :)


UPDATE: Some more code snippets:

//Code to create a new list item
function PerformCreateStuff() {

//create promise
var dfd = new $.Deferred();

var listName = "MyList";
var listItemEntityTypeFullName = "SP.Data.MyListListItem";

//prepare the data
reqData = JSON.stringify({
'__metadata': { 'type': listItemEntityTypeFullName },
'Title': "New item"
//more columns here...
});


//get digest
$.ajax({
url: appweburl + '/_api/contextinfo',
method: "POST",
headers: { "Accept": "application/json; odata=verbose" }
}).done(function (data) {
var requestDigest = data.d.GetContextWebInformation.FormDigestValue;

//create the list item
$.when(CreateHostListItem(appweburl, hostweburl, listName, reqData, requestDigest)).done(function (data) {
var newId = data.Id;
dfd.resolve(newId);
}).fail(function (object, errorCode, errorMessage) {
alert(errorMessage);
debugger;
});
});

}

//helper method
function CreateHostListItem(appweburl, hostweburl, listName, reqData, reqDigest) {

    var dfd = new $.Deferred();
    var reqUrl, reqHeaders;

    reqUrl = appweburl +
            "/_api/SP.AppContextSite(@target)/web/lists/getbytitle('" + listName + "')/items?@target='" +
            hostweburl + "'";

    if (reqDigest == null)
        reqDigest = $("#__REQUESTDIGEST").val();

    reqHeaders = {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
        "content-length": 0,
        "X-RequestDigest": reqDigest
    };

    $.when(PostToHostList(appweburl, hostweburl, listName, reqUrl, reqData, reqHeaders)).done(function (data) {
        dfd.resolve(data);
    }).fail(function (object, errorCode, errorMessage) {
        alert(errorMessage);
        dfd.reject(errorMessage);
    });


    //Return the Promise
    return dfd.promise();
}


//Generic method used for create and update
function PostToHostList(appweburl, hostweburl, listName, reqUrl, reqData, reqHeaders) {

    var dfd = new $.Deferred();
    var executor = new SP.RequestExecutor(appweburl);


    executor.executeAsync({
        url: reqUrl,
        method: "POST",
        body: reqData,
        headers: reqHeaders,
        success: successHandler,
        error: errorHandler
    });

    function successHandler(data) {
        if (data != null && data != "" && data.body != null & data.body != "") {
            var jsonObject = JSON.parse(data.body);
            var result = jsonObject.d;
            dfd.resolve(result);
        } else {
            dfd.resolve();
        }

    }

    function errorHandler(object, errorcode, errorMessage) {
        alert(errorMessage);
        dfd.reject(errorMessage);
        debugger;
    }

    //Return the Promise
    return dfd.promise();

}




Posted on Tuesday, October 6, 2015 8:48 PM jquery , sharepoint , REST , add-in | Back to top


Comments on this post: Creating a SharePoint list item from an app/add-in part - fun with form digest

# re: Creating a SharePoint list item from an app/add-in part - fun with form digest
Requesting Gravatar...
Hi,
Very interesting but in my Client App Part does not work :(
You could put all the code please.
Thanks a lot!
Left by Alex on Jan 07, 2016 4:00 PM

# re: Creating a SharePoint list item from an app/add-in part - fun with form digest
Requesting Gravatar...
Hi Alex,

unfortunately I am not allowed to post the whole working code, but I have taken an excerpt and modified it slightly to remove all business sensitive stuff. I cannot guarantee it is running, but it should at least show the principle.

If you are still facing problems, tell me more about your error, and I might be able to help.
Left by Thorvald on Jan 08, 2016 11:15 AM

Your comment:
 (will show your gravatar)


Copyright © Thorvald Bøe | Powered by: GeeksWithBlogs.net