TIP using SP.RequestExecutor to access data in SharePoint 2013 hosted apps with AngularJS cross domain

Background: In my current project developing a SharePoint 2013 hosted app where all the UI is developed in AngularJS presentation framework while using SharePoint host site collection and subsites for storing data in lists, security, version control, etc.  Convinced this is the best way to develop great UI in SharePoint after seeing the results of using AngularJS presentation framework for UI and SharePoint hosted app for the data.  There are a couple custom WCF services and also Node.js in the mix as well-very cool and the client very happy with the speed and responsiveness of the single page app.

In the process though, ran into a couple interesting aspects of accessing data from lists stored in both the SharePoint host site collection and subsites.  The few examples I found are from Jeremy Thake here and Andrew Connell here and recommend both since they are excellent.  But overall the web is a little sparse working with data in the host site collection/subsites using the SharePoint cross domain access via SP.RequestExecutor. The one I started from is a decent post on http://msdn.microsoft.com/en-us/library/office/fp179927%28v=office.15%29.aspx#SP15Accessdatafromremoteapp_Hostweb but there are few details when working with AngularJS routes had to work out in addition so sharing for those working on similar projects.

Tips for avoiding issues accessing SharePoint lists in the host site collection/subsites web in a SharePoint 2013 hosted app and angularJS routing.

TIP 1: Avoiding SP not defined issue: ensure the appurl passed to SP.RequestExector cross domain does not contain unacceptable characters in the url obtained from the querystring parameters.

One example being the angularJS “#/” that can get appended to the SPAppWebURL in the querystring

One slightly frustrating issue easy to miss was with the appweburl used by SP.RequestExecutor. Watch out for the SPAppWebURL obtained from the querystring when using SharePoint cross-domain access and AngularJS routes. If SP.Requestor sees the “#/” you may get an error displayed in FireFox as “SP not defined“.

Example URL:
http://app-33fd23755c4644.apps.smartek21:20982/AmazonRodUpdates/Pages/app.html?SPHostUrl=http%3A%2F%2Fwin-6viq5heh7nd%3A20982&SPLanguage=en-US&SPClientTag=0&SPProductNumber=15.0.4569.1000&SPAppWebUrl=http%3A%2F%2Fapp-33fd23755c4644.apps.smartek21%3A20982%2FAmazonRodUpdates#/goals

Removing the “#/” from the appweburl is one way to resolve this issue.

appweburl = decodeURIComponent(getQueryStringParameter(“SPAppWebUrl”)).split(“#/”)[0];

//Get the URI decoded URLs.
hostweburl = decodeURIComponent(getQueryStringParameter(“SPHostUrl”));
//appweburl = decodeURIComponent(getQueryStringParameter(“SPAppWebUrl”));
appweburl = decodeURIComponent(getQueryStringParameter(“SPAppWebUrl”)).split(“#/”)[0];
var scriptbase = hostweburl + “/_layouts/15/”;

// Load the js files and continue to the successHandler

$.getScript(scriptbase + “SP.RequestExecutor.js”, loadUser);

function getQueryStringParameter(paramToRetrieve) {
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] == paramToRetrieve)
return singleParam[1];
}
}

TIP 2: Avoiding scoping issues: ensure you set the proper scope for accessing SharePoint list data in subsites and/or cross site collections

When accessing lists stored in subsites in the host web set the scope to tenant in AppManifest/xml

<AppPermissionRequests>
<AppPermissionRequest Scope=”http://sharepoint/content/tenant&#8221; Right=”Write” />
<AppPermissionRequest Scope=”http://sharepoint/content/sitecollection/web/list&#8221; Right=”Write” />
<AppPermissionRequest Scope=”http://sharepoint/content/sitecollection/web&#8221; Right=”Write” />
</AppPermissionRequests>
Example AngularJS routing used:

var goalsApp = angular.module(‘goalsApp’, [‘ui.bootstrap’, ‘ui.bootstrap.tpls’, ‘ui.router’, ‘ngGrid’]);

goalsApp.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {

$urlRouterProvider.otherwise(‘/goals’);

$stateProvider

// HOME STATES AND NESTED VIEWS

.state(‘dashboard’, {
url: ‘/dashboard’,
templateUrl: ‘../apps/partials/dashboard/dashboard.html’,
controller: ‘dashboard’,
controllerAs: ‘vm’
})
//nest projects on dashboard page
.state(‘dashboard.projects’, {
url: ‘/projects’,
templateUrl: ‘../apps/partials/projects/projects.html’,
controller: ‘projects’,
controllerAs: ‘vm’
})

// customers
.state(‘customers’, {
url: ‘/customers’,
templateUrl: ‘../apps/partials/customers/customers.html’,
controller: ‘customers’,
controllerAs: ‘vm’
})

// goals
.state(‘goals’, {
url: ‘/goals’,
templateUrl: ‘../apps/partials/goals/goals.html’,
controller: ‘businessreview’,
controllerAs: ‘vm’
})

});

AngularJS and SharePoint 2013 together-loving it!

Rod Stagg

http://rstagg.com

Advertisements