In-Depth

Where JavaScript and SharePoint Apps Intersect

SharePoint is versatile, in that developers can interact with its data via other programming languages besides what's in Visual Studio. Here's how AngularJS fits into the development mix.

With SharePoint 2013, Microsoft wants developers to reduce the workload they put on servers and maximize the use of client-side rendering to the best possible extent. With the availability of the REST API and JavaScript object model, Microsoft has enabled interacting with SharePoint data through many other programming languages and frameworks.

One such popular JavaScript framework is AngularJS, which has been getting lots of attention lately and comes with the promise of helping to build next-generation front-end customizations. It provides easy and smart ways to use less code through data binding and dependency injection. In turn, these features reduce server-side rendering by minimizing server requests and handling a considerable amount of workload in the Web browser.

AngularJS provides another way of giving dynamic looks to static documents with the help of new HTML constructs, called directives. I'd especially emphasize these AngularJS features:

  • DOM event handling
  • Two-way data binding
  • Easy to use DOM control structures
  • Ways to interact with form validations

All of these features support building Create-Read-Update-Delete (CRUD) operations within applications, but it's not just about enabling CRUD operations but also about testability. You can use AngularJS for Ununit testing as well as mock testing with the available features.

Key AngularJS Concepts
Before going into the integration of AngularJS with SharePoint, let's look at some basic principles of AngularJS that I believe are worth noting:

Directives: Directives apply special behaviors to the attributes or the elements in HTML. They can be further defined as the markers on DOM elements that tell the AngularJS HTML compiler to attach a specific behavior to the DOM element and make transitions if necessary. They basically start with an "ng" prefix and there are a set of predefined set of directives from which you can add custom directives. Here are some of the basic directives that you'll most frequently use:

  • Ng-app: Defines a root scope from where the framework gets active.
  • Ng-controller: Uses a custom JavaScript file to define the content that needs to be managed within the particular scope where it is defined.
  • Ng-repeat: Displays an item collection in a repetitive template with the required properties defined within the repeated element.

Model: A model can be defined as a set of data that is to be shown to the users. There can be model elements that exist within a page and that data can be directly bound to reflect on the page very easily.

Scope: Scope is an object that refers to the application model. It can be also considered as an execution context for the expressions where we can write some AngularJS expressions to display some data, do some operations and so on.

Data binding: Data binding is simplified with a standard syntax and with ability to add filters to in in easy ways. They allow a specific model element defined in a scope to be displayed within html with the following syntax.

Now, let's create a SharePoint hosted app via AngularJS.

Create the SharePoint Hosted App
Open Visual Studio 2013 and create a new SharePoint App named Angular.App. Then go to http://angularjs.org and download the latest stable release of AngularJS framework. The version that was available as I wrote this article was version 1.3x. From that, I selected the minified version.

Now right-click on the Scripts folder and add the downloaded file to the scripts folder. It should be visible (see Figure 1). If I just deploy the app and browse it, it should show the default page.

Adding AngularJS files
[Click on image for larger view.] Figure 1: Adding AngularJS files

Now empty the content inside the App.js file within the script folder and add the following reference to the head section of the Default.aspx file:

<script type="text/javascript" src="../Scripts/angular.min.js"></script>

Then replace the content inside the asp:Content tag with ID attribute PlaceHolderMain with the following content:

<div ng-app="">
  <p>My name is:
  <input type="text" ng-model="name"></p>
  <p>Welcome {{name}}</p>
  </div>

Now deploy the app and check browsing (see Figure 2). As you keep typing your name in the textbox you can see the welcome message getting updated. That is because there is a strict binding of the model property, which is called name. This is a simple example and a source for assurance on correct configuration of AngularJS within SharePoint.

Deploying the App
[Click on image for larger view.] Figure 2: Deploying the App

As you can see, we are using the ng-model directive and another directive named ng-app. The ng-app directive designates the root element of the application and is typically placed near the root element of the page or where AngularJS need to be active.

Two other concepts worth noting as we proceed further are the Controllers and the Services.

The controllers in AngularJS attach a controller class to a view. This is one of the key components, given AngularJS supports the MVC design pattern implementation. Controller for a particular view can be defined with the ng-controller directive.

Services in AngularJS provide a greater way to connect the objects using a software design pattern known as dependency injection. Services are normally used for organizing and sharing the code across a particular app. Given it uses dependency injection, a service is only initiated when an application component feels the need to depend on it.

There are some built-in services that starts with the "$" tag such like "$http". Most of the time we end up writing our own service to take care of any other required functionality.

All these services, directives and other AngularJS components are initialized through a concept called Modules in AngularJS. Modules make code easier to unit test and debug as well as improves the portability of the code to a greater extent.

Connecting to SharePoint List Data
To demonstrate the interaction with AngularJS and SharePoint, let's create a list that contains movie names. Right-click on the Visual Studio project and proceed with Add | New | List and name the project as "Movies." Select the custom list template as the list template.

Open the list template in Visual Studio and add two new columns, "Directors" and "Year," which will be single line of text fields (see Figure 3). This will create a list named Movies in the App Web each time it is deployed.

Movies List
[Click on image for larger view.] Figure 3: Movies List

Now let's see how we can show the list items added to this SharePoint list within a SharePoint page.

First replace the content inside the asp:Content tag with the ID PlaceHolderMain with following HTML. This was earlier changed to display a basic AngularJS model binding:

<div ng-app="store">
  <div ng-controller="movieController" >
  <ul>
  <li ng-repeat="item in movies" >
  {{item.Title}} - {{item.Year}}
  </li>
  </ul>
  </div>
  </div>

Here, I have defined an app named "store" where the AngularJS functionality will appear in the page. It can contain multiple controllers that are helpful for implementing the functionality, but in this case I just need one named "movieController." In addition to those two I have used a directive named "ng-repeat," which functions similarly like a For…Each loop that most developers are used to seeing in everyday programming languages. Just like we'd do with most object-oriented programming languages, here we can access the properties of a movie entity that is represented in a variable named "item." I've also made references to two properties, Title and Year.

Now let's add some JavaScript functionality. Go to the Scripts module and start editing the App.js file. First create a module that will create a module named "store," which is referenced in the aspx file:

var app = angular.module('store', []);

Next, assign a controller named "movieController" that is assigned for the ng-controller directive:

app.controller('movieController', function ($scope, SharePointList) {
  
  var self = this;
  self.movies = SharePointList.list();
  alert('1 ' + self.movies.length);
  
  });

As you can see I have assigned a variable named movies with a service I am creating named "SharePointList" that's shown in Listing 1.

Listing 1: SharePoint List Service

app.service('SharePointList', function () {
  
  var self = this;
  
  self.allItems = [];
  
  self.list = function () {
  EnsureScriptFunc("sp.js", "SP.ClientContext", function () {
  var loc = new SP.ClientContext(_spPageContextInfo.webServerRelativeUrl);
  
  var web = loc.get_web();
  var locList = web.get_lists().getByTitle("Movies");
  
  var query = new SP.CamlQuery();
  
  var queryString = "<View>\
  <Query>\
  <OrderBy>\
  <FieldRef Name='Title' Ascending='True'/>\
  </OrderBy>\
  </Query>\
  </View>";
  query.set_viewXml(queryString);
  
  var locItems = locList.getItems(query);
  loc.load(locItems, "Include(ID,Title,Directors,Year)");
  loc.executeQueryAsync(function () {
  var movies = [];
  var locItemEnumerator = locItems.getEnumerator();
  // Iterate through our retrieved data set and build an array of JSON objects containing
  // the relevent properties.
  while (locItemEnumerator.moveNext()) {
  
  var movieObject = new createItems({
  Year: locItemEnumerator.get_current().get_item("Year"),
  Directors: locItemEnumerator.get_current().get_item("Directors"),
  Title: locItemEnumerator.get_current().get_item("Title"),
  Id: locItemEnumerator.get_current().get_item("ID")
  });
  
  movies.push(movieObject);
  
  }
  self.allItems = movies;
  return self.allItems;
  
  }, function (sender, args) {
  alert('Loading failed. ' + args.get_message() + '\n' + args.get_stackTrace());
  });
  
  });
  };
  
  
  });
  
  function createItems(data) {
  var self = this;
  self.ID = data.ID;
  self.Title = data.Title;
  self.Year = data.Year;
  self.Directors = data.Directors;
  };

As you can see I am assigning the current instance of the client context to a variable named "self." Then I assign a function named list that will bind the existing list items to the current instance. The function inside needs to ensure the sp.js file which contains all the SharePoint client-side scripting is available.

Then I have defined a CAML query that queries the SharePoint list items to be sorted by the Title field in ascending order. Given I don't need all the columns, I query for only the ID, Title, Directors and Year fields. Thereafter it is a matter of creating the necessary objects that will be bound to the Angular UI thread.

I have added functionality to track the exceptions and errors coming on. With that I can get an idea on what goes wrong whenever something happens.

Next up is testing the app. Browse to the list created inside the app web and add some data to the list of movies you prefer to be displayed in the Default.aspx page. Once you browse back through to the Default.aspx, you will be able to see data bound to it (see Figure 4).

Data Is Bound!
[Click on image for larger view.] Figure 4: Data Is Bound!

Advantages of Using AngularJS
There are many advantages that makes AngularJS a great framework for integrating with other platforms. I've highlighted three:

Two-way data binding: This can be identified as one of the coolest features in AngularJS. This reduces the lines of code we need to write for all data related operations by many means. Data manipulation within an application logic makes most of the coding activities. AngularJS simplifies the data binding needs by operating simply within the model as the place of concern. Whenever the model gets updated, the relevant other functionalities get its reflections.

Dependency Injection: Dependency Injection is arguably one of the coolest features that comes with AngularJS. With this developer does not need to find the places need to be affected as the dependencies get defined. This makes the development process much easier and clean. Somehow some sources mention this can work badly for the performances as well in some situations.

Templates: If you are familiar with any XAML based language Microsoft introduced over the past decade, then you know the advantages of having templates defined. AngularJS simplify the templates and it makes them purely HTML based and makes it so easy to work with.

As you can see, it is really simple to get start using AngularJS with SharePoint Apps. There are many advantages as well as points of concerns to be careful with, as is always the case when integrating with another framework. As AngularJS improves, there will be more useful app integrations to come.

About the Author

Malin De Silva is a SharePoint Specialist at Exilesoft and has been involved in many custom development projects, intranets, search, and other projects using SharePoint, .NET, Java and PHP. Malin is a frequent contributor to many forums, including Sri Lanka .NET Forum and SharePoint Sri Lanka. Connect with him on LinkedIn or Facebook.

comments powered by Disqus

Featured

Subscribe on YouTube