SharePoint 2013 app - get data from the SharePoint

For safety reasons apps are seperated from the SharePoint where they are installed on. Apps are installed on other domains and that is how the seperation works. Apps can't contact the SharePoint, because Cross-Site-Scriptingis blocking it. But there is still a way to get data from the SharePoint and with this way comes a permission concept into the app world.

Permissions


There is a library, called the Cross Domain Library, that allows to communicate with a SharePoint from app site. This library is aviable on every SharePoint 2013 and is easy to call. But wait.. if it is so easy to call a library that can get SharePoint data it is not saver than before. This library contains more than communication.. it authentificates the app against the SharePoint and asks for permissions. This happens right after the installation of the app. The installing user will be asked to grand permissions for the app. But how does the app know what permissions are needed? Asking for permissions is your part. First of all you should know what your app will do. This app will query lists and will create list items, So for the list query we need read permissions on the Web object. Write permissions for a List object are needed to create items. To set this up open the AppManifest.xml file and open the 'Permissions'-tab. Here you will find a grid, where you can add the request for permissions that you need.



Installing the app will open the permission request window. This will happen with every debugging, because every installation got a different ID and for the SharePoint it is a new app.


After hitting the 'Trust It' button the app opens.

Code

After setting the permissions let us come to the code. At first I made changes in the Default.aspx file. I added a button and a paragraph. The snippet looks like this:

1
2
3
4
5
6
7
<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <div>
        <input id="getLists" type="button" value="load"/>
        <p id="lists">                                   
        </p>
    </div>
</asp:Content>

But the most changes I made are in the App.js file. At first I added a click event on the button and a initilizing function to the document ready event.

1
2
3
4
$(document).ready(function () {
    $('#getLists').click(function () { printAllListNamesFromHostWeb(); });
    sharePointReady();
});

The sharePointReady function calls the host-URL (URL of the SharePoint) and the app-URL (URL of the app). After that the function gurarantees that all scripts are loaded. Behind that follows the call of the funtion setupHostContext.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function sharePointReady() {
    // get the host url
    // the current url contains it under SPHostUrl=..
    hostweburl =
         decodeURIComponent(
             getQueryStringParameter('SPHostUrl')
     );
    // get the app url
    // the current url contains it under SPAppWebUrl=..
    appweburl =
        decodeURIComponent(
            getQueryStringParameter('SPAppWebUrl')
     );

    var scriptbase = hostweburl + '/_layouts/15/';

    // load the SP.Runtime, SP.js and SP.RequestExecutor.js libabries then call the function setupHostContext
    // the SP.RequestExecutor.js library is neccessary to authentificate against the host SharePoint
    $.getScript(scriptbase + 'SP.Runtime.js',
        function () {
            $.getScript(scriptbase + 'SP.js',
                function () { $.getScript(scriptbase + 'SP.RequestExecutor.js', setupHostContext); }
            );
        }
    );
}

The function setupHostContext prepares the communication with the SharePoint. It makes use of the SP.RequestExecutor.js library. The context of the app will be used to authentificate the user on the SharePoint. After that the context object will set to the SharePoint context and loaded.

1
2
3
4
5
6
7
8
9
function setupHostContext() {
    // build the context for the app web then build with it and the RequestExecutor library the context for the host web
    context = new SP.ClientContext(appweburl);
    factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
    context.set_webRequestExecutorFactory(factory);
    appContextSite = new SP.AppContextSite(context, hostweburl);
    web = appContextSite.get_web();
    context.load(web);
}

From here everything is like in the normal Client Side Object Modell (CSOM) for JavaScript (colloquially JSOM). Queries will be made and startet. In successfully cases you get data if not you get an error. The same way you can write objects into lists and so on. The only thing you need to remember are your permissions. What permissions do you have and what do you need. If you don't remember that you will get an error like this:


If everything worked fine you will get what you want. In our case a list of all SharePoint lists appears. The lists will be listed with textboxes and buttons. They are needed to add items to the list. The UI should look like this:


Here is the full code in the App.js file:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
var web;
var hostweburl;
var appweburl;

var context;
var factory;
var appContextSite;
var collList;

$(document).ready(function () {
    sharePointReady();
    $('#getLists').click(function () { printAllListNamesFromHostWeb(); });
});


function sharePointReady() {
    // get the host url
    // the current url contains it under SPHostUrl=..
    hostweburl =
         decodeURIComponent(
             getQueryStringParameter('SPHostUrl')
     );
    // get the app url
    // the current url contains it under SPAppWebUrl=..
    appweburl =
        decodeURIComponent(
            getQueryStringParameter('SPAppWebUrl')
     );

    var scriptbase = hostweburl + '/_layouts/15/';

    // load the SP.Runtime, SP.js and SP.RequestExecutor.js libabries then call the function setupHostContext
    // the SP.RequestExecutor.js library is neccessary to authentificate against the host SharePoint
    $.getScript(scriptbase + 'SP.Runtime.js',
        function () {
            $.getScript(scriptbase + 'SP.js',
                function () { $.getScript(scriptbase + 'SP.RequestExecutor.js', setupHostContext); }
            );
        }
    );
}

function getQueryStringParameter(param) {
    // get the current url and search in it for the param
    var params = document.URL.split("?")[1].split("&");
    var strParams = "";
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split("=");
        if (singleParam[0] == param) {
            return singleParam[1];
        }
    }
}

function setupHostContext() {
    // build the context for the app web then build with it and the RequestExecutor library the context for the host web
    context = new SP.ClientContext(appweburl);
    factory = new SP.ProxyWebRequestExecutorFactory(appweburl);
    context.set_webRequestExecutorFactory(factory);
    appContextSite = new SP.AppContextSite(context, hostweburl);
    web = appContextSite.get_web();
    context.load(web);
}

function printAllListNamesFromHostWeb() {
    // build a query to the host web   
    collList = web.get_lists();
    context.load(collList);

    // execute the query
    context.executeQueryAsync(
        Function.createDelegate(this, successHandler),
        Function.createDelegate(this, errorHandler)
    );

    function successHandler() {
        // query successfully.. display the result
        var listInfo = '';
        var listEnumerator = collList.getEnumerator();

        while (listEnumerator.moveNext()) {
            var oList = listEnumerator.get_current();

            var title = oList.get_title();
            listInfo += '<tr><td>' + title + '</td><td><input type="text" id="txt' + title + '" /></td><td><input value="add" type="button"  onClick="addItem(\'' + title + '\');" /></td></tr>';
        }

        $('#lists').html('<table><tr><td>Lists</td><td>new Item</td><td></td></tr>' + listInfo + '</table>');
    }

    function errorHandler(sender, args) {
        // query failed
        $('#lists').text('Could not complete cross-domain call: ' + args.get_message());
    }
}



function addItem(listTitle) {
    var oList = collList.getByTitle(listTitle);

    var itemCreateInfo = new SP.ListItemCreationInformation();
    var oListItem = oList.addItem(itemCreateInfo);
    oListItem.set_item('Title', $('#txt' + listTitle).val());
    oListItem.update();

    context.load(oListItem);

    context.executeQueryAsync(
        Function.createDelegate(this, onQuerySucceeded),
        Function.createDelegate(this, onQueryFailed)
    );


    function onQuerySucceeded() {
        alert('Item created: ' + oListItem.get_id());
        $('#txt' + listTitle).val('');
    }

    function onQueryFailed(sender, args) {
        alert('Request failed. ' + args.get_message() +
            '\n' + args.get_stackTrace());
    }
}

Comments

Popular posts from this blog

How to support multiple languages in WPF