The App Model introduced in SharePoint 2013 allows JavaScript Developers to develop Apps for SharePoint. In SharePoint 2013, everything (which includes Lists, Libraries etc.) is an application. The JavaScript programming feature of App for SharePoint executes the custom code on a separate server e.g. Cloud, IIS, or even the client browser. There are several JavaScript Libraries and Frameworks for DOM manipulations, and implementing MVVM and MVC programming on client-side. Some of them includes jQuery, Knockout, Angular.js etc. In this article, we will build a SharePoint Application using AngularJS. The Services and Controller features of Angular.js can be used to manage the SharePoint model declaration (controller scope objects) and external service calls (services) segregation will help to develop Apps for SharePoint effectively. We will be using SharePoint 2013 Online and the Developer site created on it.
Step 1
Open the SharePoint online portal using http://portal.microsoftonline.com. Login with your subscription. (Alternatively, on-premises SharePoint 2013 installation can be used). Create a new developer site and a Custom List named CategoryList as shown in the following figure:
The list will have CategoryId and CategoryName columns. Note that the default Title Column is renamed to CategoryId. The programming always uses the Title as column name.
Step 2
Open Visual Studio 2013 and create a new App for SharePoint and name it SPNG as shown in the following figure.
Set the SharePoint site for SharePoint hosted App as shown in the following figure:
Once the app is created add the AngularJS Framework, jQuery and Bootstrap JavaScript libraries using Manage NuGet Package in the project.
Step 3
In the Scripts folder, add a new folder and name it MyScripts. In this folder, add the following JavaScript files:
Module.js
1 2 3 |
(function () { angular.module('spsmodule', []); })(); |
The above code is for creating an Angular.js module. This is the entry point for our application.
Service.js
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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
(function (app) { app.service('spsservice', function ($q) { function manageQueryStringParameter(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]; } } } var hostWebUrl; var appWebUrl; //The SharePoint App where the App is actualy installed hostWebUrl = decodeURIComponent(manageQueryStringParameter('SPHostUrl')); //The App web where the component to be accessed by the app are deployed appWebUrl = decodeURIComponent(manageQueryStringParameter('SPAppWebUrl')); //Function to read all records this.get = function () { var deferred = $q.defer(); //Get the SharePoint Context object based upon the URL var ctx = new SP.ClientContext(appWebUrl); var appCtxSite = new SP.AppContextSite(ctx, hostWebUrl); var web = appCtxSite.get_web(); //Get the Web var list = web.get_lists().getByTitle("CategoryList"); //Get the List var query = new SP.CamlQuery(); //The Query object. This is used to query for data in the List query.set_viewXml('<View><RowLimit></RowLimit>10</View>'); var items = list.getItems(query); ctx.load(list); //Retrieves the properties of a client object from the server. ctx.load(items); //Execute the Query Asynchronously ctx.executeQueryAsync( Function.createDelegate(this, function () { var itemInfo = ''; var enumerator = items.getEnumerator(); var CategoryArray = []; while (enumerator.moveNext()) { var currentListItem = enumerator.get_current(); CategoryArray.push({ ID: currentListItem.get_item('ID'), CategoryId: currentListItem.get_item('Title'), CategoryName: currentListItem.get_item('CategoryName') }); } deferred.resolve(CategoryArray); }), Function.createDelegate(this, function (sender, args) { deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); }) ); return deferred.promise; }; //Function to Add the new record in the List this.add = function (Category) { var deferred = $q.defer(); //debugger; var ctx = new SP.ClientContext(appWebUrl);//Get the SharePoint Context object based upon the URL var appCtxSite = new SP.AppContextSite(ctx, hostWebUrl); var web = appCtxSite.get_web(); //Get the Site var list = web.get_lists().getByTitle("CategoryList"); //Get the List based upon the Title var listCreationInformation = new SP.ListItemCreationInformation(); //Object for creating Item in the List ctx.load(list); var listItem = list.addItem(listCreationInformation); listItem.set_item("Title", Category.CategoryId); listItem.set_item("CategoryName", Category.CategoryName); listItem.update(); //Update the List Item ctx.load(listItem); //Execute the batch Asynchronously ctx.executeQueryAsync( Function.createDelegate(this, function () { var Categories = []; var id = listItem.get_id(); Categories.push({ ID: listItem.get_item('ID'), CategoryId: listItem.get_item('Title'), CategoryName: listItem.get_item('CategoryName') }); deferred.resolve(Categories); }), Function.createDelegate(this, function () { deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); }) ); return deferred.promise; } //Method to Update update the record this.update = function (Category) { var deferred = $q.defer(); var ctx = new SP.ClientContext(appWebUrl); var appCtxSite = new SP.AppContextSite(ctx, hostWebUrl); var web = appCtxSite.get_web(); var list = web.get_lists().getByTitle("CategoryList"); ctx.load(list); listItemToUpdate = list.getItemById(Category.ID); ctx.load(listItemToUpdate); listItemToUpdate.set_item('CategoryName', Category.CategoryName); listItemToUpdate.update(); ctx.executeQueryAsync( Function.createDelegate(this, function () { var Categories = []; var id = listItemToUpdate.get_id(); Categories.push({ ID: listItemToUpdate.get_item('ID'), CategoryId: listItemToUpdate.get_item('Title'), CategoryName: listItemToUpdate.get_item('CategoryName') }); deferred.resolve(Categories); }), Function.createDelegate(this, function () { deferred.reject('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace()); }) ); return deferred.promise; }; }); }(angular.module('spsmodule'))); |
Controller.js
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 |
(function (app) { app.controller('spscontroller', function ($scope,spsservice) { load(); $scope.Categories = []; $scope.Category = { ID:0, CategoryId: "", CategoryName:"" }; var IsUpdate = false; //Function to load all categories function load() { var promiseGet = spsservice.get(); promiseGet.then(function (resp) { $scope.Categories = resp; }, function (err) { $scope.Message = "Error " + err.status; }); } //Function to load the selected record $scope.loadRecord = function (cat,$event) { $event.preventDefault(); $scope.Category.ID = cat.ID; $scope.Category.CategoryId = cat.CategoryId; $scope.Category.CategoryName = cat.CategoryName; IsUpdate = true; } //Function to Create a new category or update existing base on the //IdUpdate boolean $scope.save = function ($event) { $event.preventDefault(); if (!IsUpdate) { var promiseSave = spsservice.add($scope.Category); promiseSave.then(function (resp) { alert("Saved"); }, function (err) { $scope.Message = "Error " + err.status; }); } else { var promiseUpdate = spsservice.update($scope.Category); promiseUpdate.then(function (resp) { alert("Saved"); }, function (err) { $scope.Message = "Error " + err.status; }); IsUpdate = false; } } }); }(angular.module('spsmodule'))); |
Step 4
Open Default.aspx and add the following script references:
1 2 3 4 5 6 7 8 9 10 11 |
<script src="../Scripts/jquery-2.1.3.min.js"></script> <script src="../Scripts/bootstrap.min.js"></script> <script src="../Scripts/angular.min.js"></script> <script src="../Scripts/angular-ui/ui-bootstrap-tpls.min.js"></script> <script src="../Scripts/MyScripts/module.js"></script> <script src="../Scripts/MyScripts/service.js" ></script> <script src="../Scripts/MyScripts/controller.js" ></script> <link href="../Content/bootstrap-theme.min.css" rel="stylesheet" /> <link href="../Content/bootstrap.min.css" rel="stylesheet" /> |
The above references are used to load Angular Framework and the bootstrap library for the RICH UI.
Step 5
Add the following markup in the PlaceHolderMain of Default.aspx:
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 |
<div ng-app="spsmodule"> <div ng-controller="spscontroller"> <hr /> <br /> <div id="dvdml"> <table class="table table-condensed table-striped table-bordered"> <tr> <td>Category Id:</td> <td> <input type="text" class="form-control" ng-model="Category.CategoryId" /> </td> </tr> <tr> <td>Category Name:</td> <td> <input type="text" class="form-control" ng-model="Category.CategoryName"> </td> </tr> </table> </div> <input type="button" id="btnaddcategory" class="btn btn-small btn-primary" value="Save" ng-click="save($event)"/> <br /> <table class="table table-bordered table-striped"> <thead> <tr> <th class="c1">RecordId</th> <th class="c1">CategoryId</th> <th class="c1">CategoryName</th> <th class="c1"></th> <th class="c1"></th> </tr> </thead> <tbody> <tr ng-repeat="Cat in Categories|orderBy:'CategoryId'"> <td>{{Cat.ID}}</td> <td>{{Cat.CategoryId}}</td> <td>{{Cat.CategoryName}}</td> <td> <button class="btn glyphicon glyphicon-pencil" ng-click="loadRecord(Cat,$event)"/> </td> </tr> </tbody> </table> </div> </div> |
Step 6
Since we need to perform a Read/Write operations on the List using App, we need to apply access rights. In the project we have an AppManifest.xml. This is used to set the App permissions. Double-Click on this file and set the permissions as shown in the following figure:
Step 7
Here we need to set permissions on the Web Sire and the List, so that we can perform Read/Write operations.
Run the application, after deployment we can set the trust for the app as shown here. Click on Trust It and the following result will be displayed:
Enter Category Details in the textboxes and click on the Save button, the new category record added in the table will be displayed as shown in the following figure:
Happy coding!
Looking for SharePoint Hosting on European Server? We can help you a lot!
hostforlifeasp.net is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes. We have customers from around the globe, spread across every continent. We serve the hosting needs of the business and professional, government and nonprofit, entertainment and personal use market segments.