Accelerate SharePoint Development with AngularJS

by Uma Narayanan

Introduction

With client-side MVC tools getting popular, there is lot of focus on leveraging AngularJS as a platform for building modern web single page applications (SPA). In the .NET world, there is increasing demand for using AngularJS with Web API services to create responsive applications supporting a variety of devices with different form factors. An obvious extension to that is using AngularJS to build a SharePoint UI.

In this article, you will learn some of the benefits of using AngularJS with SharePoint 2013. There are a couple of ways in which you can use AngularJS with SharePoint:

  • You can use it in an app model with any kind of hosting option.
  • You can create HTML files and add them to content editor web parts on site pages.

This article focuses on the second option.

Overview

Before looking at the code on how to leverage AngularJS, let us understand how AngularJS makes the creating applications easy, modularized, and testable.

Anyone who has worked with SharePoint knows a few ways to customize SharePoint for an interactive UI, such as:

  • Developing Web Parts
  • Creating an application page or a feature page with some backend code
  • It can also be HTML and JQuery. Using native JQuery increases the code in general and can become complicated, losing readability, and so forth.

When using JS Frameworks, many features are provided by the framework itself, such as the concept of binding data, looping, and hiding/displaying a section. AngularJS also provides concepts like modeling, routing, custom directives, and services.

Today, we will take a basic example that demonstrates Angular binding. The concept can be extended to routing, directives, services, and other features of Angular.

Some of the advantages of using AngularJS framework with SharePoint are:

  • It's completely client-side coding; in other words, it can be developed and deployed without the IT admin's intervention.
  • The JS framework improves performance because the reload of a page is minimum (unless explicit).
  • Data binding is a two-way binding; if the value of the variable is changed anywhere in the model, the UI is automatically updated.

[Look for Angular documentation at https://angularjs.org/]

Examples Where AngularJS Can Be Leveraged

AngularJS is very useful when developing an interactive dashboard with multiple areas/sections in a page. It also can be used to develop an entry screen UI, where the user is adding multiple items to the cart before clicking on submit and, on submission, it saves the data in a SharePoint List.

Other examples could be customizing search results displaying results in a custom UI and implementing a 'Like' feature on the search results, hide/show a button or a link, or a section in a page based on the user's permission.

How to Use in SharePoint

In SharePoint, the data resides in lists or libraries and list/libraries have columns. To implement AngularJS, we will need three kinds of files (all three can be added to an HTML file itself but that's not a good practice):

  • The HTML files serve as views.
  • The JS file contains the codeL the model, controller, and other objects' definition and implementations.
  • The CSS files contain the styles for the views.

So, we create three folders named 'View', 'JavaScript', and 'Styles' in the 'SiteAssets' library, as shown in Figure 1:

SharePoint AngularJS
Figure 1: The three folders are in the library

As the name signifies, the respective files will be placed in their respective folders.

Create three files (one CSS, one App.js, and an HTML file) with some comments and upload them to the respective folders. As we progress with the code, we will keep updating these files.

The next step is to create a web part page in the 'Site Pages' library and add a content editor web part to the page.

In the tool part of the content editor web part, add a relative URL of the HTML file previously uploaded in the SiteAssets library, shown in Figure 2.

SharePoint AngularJS
Figure 2: Adding the URL

This completes the initial setup. Now, we will look at the code that will be placed in these files.

Description

Let's understand how to use AngularJS and SharePoint to develop a custom UI with the help of an example. In this example, we will build the following UI (see Figure 3).

Here, we are displaying documents that are added to the library, with the features "Like" and "Share". Also, based on the logged-in User's permission, some links are displayed or hidden.

SharePoint AngularJS
Figure 3: Building the User Interface

We will inspect the JavaScript code first and then the HTML UI binding part. The JavaScript code described below is added in the 'App.js' file and uploaded to the JavaScript folder in the 'SiteAssets' library.

First and foremost, we define a module and then the controller:

   var app = new angular.module("mainApp", []);

In the controller, we define an array named 'RecentDocs' to store metadata related to the documents uploaded in a library named 'Tutorials'. Also, we define an 'init' function to populate the 'Recentdocs' collection.

   app.controller("DocController", function ($q, $scope) {
      $scope.RecentDocs = [];
      $scope.RecentDoc = {};

      $scope.init = function () {

      }

In the 'init' method, the SharePoint Client Object model is used to retrieve the documents from the library.

 1. var url = _spPageContextInfo.webServerRelativeUrl;
 2. var context = new SP.ClientContext(url);
 3. web = context.get_web();
 4. var currentUser = web.get_currentUser();
 5. var oList = context.get_web().get_lists().getByTitle('Tutorials');
 6. var camlQuery = new SP.CamlQuery();

 7. camlQuery.set_viewXml('<View><RowLimit>100</RowLimit></View>');
 8. var collListItem = oList.getItems(camlQuery);
 9. context.load(currentUser);
10. context.load(web, 'EffectiveBasePermissions');
11. context.load(oList);
12. context.load(collListItem, 'Include(Id,Title,ShortDesc,Category,LikedBy,LikesCount)');
13. $scope.collListItem = collListItem;

Code Sample 1

Line 10 gets the current user's permissions for the web. This will be used, in this example, to Show/Hide some links. In Line 12, we have included LikedBy and LikesCount to implement the Like/UnLike functionality.

The next step is to execute the query to populate all the objects; the list, item collection, AND current logged-in user's permissions for the web.

 1. context.executeQueryAsync(
 2.    function () {},           //success
 3.    function (sender, args)   //failure
 4.    {
 5.        alert(args.get_message());
 6.    });

Code Sample 2

The success section in Code Sample 2 (Line 2) contains the following code that enumerates through the result and populate the 'RecentDocs' collection.

 1. var listItemEnumerator = collListItem.getEnumerator();
 2. var docs = [];

 3. if (web.get_effectiveBasePermissions().has(SP.PermissionKind.manageWeb))
 4.    $scope.IsAdmin = 1;
 5. else
 6.    $scope.IsAdmin = 0;

Code Sample 3

Line 3 checks if the current user has manage permissions for the web and accordingly sets the 'IsAdmin' model value. Based on this value, the link will be visible or hidden.

 7. while (listItemEnumerator.moveNext()) {
 8.    var oListItem = listItemEnumerator.get_current();
 9.    var likedBy = oListItem.get_item('LikedBy');
10.    var isLiked = false;
11.    var likeDisplay = "Like";
12.    var likeCount = oListItem.get_item('LikesCount');

Code Sample 4

Lines 9 and 12 gets the 'liked by' and 'likes count'. 'Liked By' is used to check whether the current user has liked this item before or not. If the current user has liked the item before, it displays the text 'Unlike'; otherwise, it displays 'Like'.

Steps 16-21 check if the display text should be like or unlike.

13.    if (likeCount == null)
14.        likeCount =0;
15.    if (!SP.ScriptHelpers.isNullOrUndefined(likedBy)) {
16.       for (var i = 0; i < likedBy.length; i++) {
17.          var like = likedBy[i];
18.          if (like.get_lookupId() === _spPageContextInfo.userId) {
19.              isliked = true;
20.              likeDisplay = "UnLike";
21.              break;
22.          }
23.       }
24    }
25.
26.   docs.push({
27.        Id: oListItem.get_id(),
28.        ListId: ListId = oList.get_id(),
29.        Title: oListItem.get_item('Title'),
30.        ShortDesc: oListItem.get_item('ShortDesc'),
31.        Category: oListItem.get_item('Category'),
32.        LikedBy: likedBy,
33.        LikedCount: likeCount,
34.        LikeDisplay: likeDisplay,
35.     });
36. }

Code Sample 5

Lines 27-35 form a JSON and adds it to the docs array.

37. $scope.RecentDocs = docs;
38. $scope.$apply();

Code Sample 6

Line 38 assigns the doc collection to the angular $scope object. $apply is a system-defined method that will re-bind the data to the HTML. It's used in case the re-binding doesn't happen automatically.

Until this stage, we have defined the 'init' method but not yet called it.

 1. RegisterSod("reputation.js", _spPageContextInfo.webAbsoluteUrl +
       "/_layouts/15/reputation.js");
 2. RegisterSodDep("reputation.js", "sp.js");
 3. SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function () { $scope.init() });

Code Sample 7

Steps 1 and 2 register reputation.js, which is used to implement the 'Like'/'UnLike' functionality. Step 3 will load SP.js and the context and then call the 'init' method.

Let's Look at the HTML to Bind the Data

Open the HTML file and place the following markup and upload the file to the View folder.

 1.<div ng-app=mainApp>
 2.
 3.    <script type="text/javascript"
 4.            src="../SiteAssets/JavaScript/angular.min.js"></script>
 5.    <script type="text/javascript"
 6.            src="../SiteAssets/JavaScript/app.js"></script>
 7.
 8.    <div class="RecentlyAdded Recommended" ng-controller="DocController">
 9.    <div class="RAItem" ng-repeat="rdoc in RecentDocs">
10.       <div class="RADetails">
11.          <h3><a href="#">{{rdoc.Title}} </a></h3>
12.          <p>{{rdoc.ShortDesc}} {{ Category}}</p>
13.          <ul>
14.             <li>
15.                <a href ng-click="OnLike(rdoc)">{{rdoc.LikeDisplay}} ({{rdoc.LikedCount}}</a>
16.             </li>
17.             <li><a href="#" ng-show="IsAdmin">Share</a></li>
18.             <li><a href="#" ng-hide="IsAdmin">Save</a></li>
19.          </ul>
20.       </div>
21.    </div>
22.    </div>
23. </div>

Code Sample 8

Line 1: ng-app with the module name informs the compiler to treat the HTML section as an Angular application.

Line 8: Binds the controller that was defined in the script by using the ng-controller directive. ng-repeat, at Line 9, loops through the RecentDocs collection that was declared in the controller and initialized in the 'init' method.

Line 11: {{rdoc.Title}} displays the metadata of the document.

In Line 15. ng-click binds the click event to the '<a>' anchor tag. The ng-click directive has a value 'OnLike', which means the on-Click on anchor tag 'OnLike' method will be executed. It takes the current SPItem, 'rdoc', as a parameter.

In Lines 17-18. ng-show displays the element if the expression 'IsAdmin' is evaluated to be true. Similarly, ng-hide hides the element.

Let's now have a look at the 'OnLike' method defined in controller.

 1. $scope.OnLike = function (rdoc) {
 2.    SP.SOD.executeFunc('reputation.js', 'Microsoft.Office.Server.ReputationModel.Reputation',
 3.    function () {
 4.       var isLiked = false;
 5.          if (rdoc.LikeDisplay == 'Like') {
 6.             rdoc.LikeDisplay = 'UnLike';
 7.             isLiked = true;
 8.          }
 9.          else {
10.             rdoc.LikeDisplay = 'Like';
11.          }

12.          var context = SP.ClientContext.get_current();
13.          Microsoft.Office.Server.ReputationModel.Reputation.setLike(context, rdoc.ListId,
                                                                        rdoc.Id, isLiked);
14.          context.executeQueryAsync(function () {
15.             if (isLiked === true) {
16.                rdoc.LikedCount = (rdoc.LikedCount + 1);
17.             }
18.             else {
19.                rdoc.LikedCount = (rdoc.LikedCount - 1);
20.
21.             }
22.
23.             $scope.$apply();

24.
25.             }, function (sender, args) { alert(args.get_message());});
26.          });
27.       };

Code Sample 9

Microsoft.Office.Server.ReputationModel.Reputation.setLike at Line 13 of Code Sample 9 is the method that toggles the Like/UnLike value for the item in the SP list.

Lines 1-11 initialize the value for the display text and the parameters to be passed to the Reputation.setLike method.

Lines 15-26 are executed when setLike is run successfully. It increases the current count by 1 or reduces the count by 1.

Summary

In this example, we saw how we can integrate the AngularJS framework with SharePoint by defining an HHTML page and adding that HTML page to any content editor web part. This concept can be extended to use routes, directives, and other features and build interactive UI pages without refreshing the whole page.

References



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

  • On-demand Event Event Date: October 29, 2014 It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds