Create your first Single Page App in SharePoint Server 2013

Sivarajan Raju
 
SharePoint Consultant
December 31, 2012
 
Rate this article
 
Views
27159

Recent trends in building applications seems to be tending towards the concept of Single Page Application (SPA) . Microsoft also seems to be adopting to this concept as seen in SharePoint 2013 Team site and few other templates that have been developed using SPA concept. For example,

http://win12/_layouts/15/start.aspx#/Lists/DraftApps/AllItems.aspx
http://win12/_layouts/15/start.aspx#/Shared%20Documents/Forms/AllItems.aspx

So lets explore the methodology for creating a SPA application in SharePoint 2013. The base page will be start.aspx and all the document libraries will be loaded internally without any page post back and also it will maintain page history and we cannot expect page history in AJAX based development.

We have a lot of JavaScript libraries available to develop a SPA and finding the right libraries for SPA development is no straight forward.

You can find a lot of SPA related information from JOHN PAPA website and also a working online demo here. The demo site has been developed using the following technologies.

ASP.NET MVC 4.5

ASP.NET Web API

Entity Framework 5.1

jQuery

Knockout JS

Sammy JS

Toaster JS

HTML 5

So I plan to bring the SPA concepts inside the SharePoint using the following technologies.

SharePoint list a data store

ListData.svc or ECMA Script for data retrieval from the SharePoint list

Knockout JS for client data binding

jQuery/jQuery template UI rendering

Sammy JS for page navigation/history maintenance

Toaster JS for notification

For this, we will see how to use this each libraries through a simple examples. First we will explore how to use Knockout with SharePoint.

Integrate Knockout with SharePoint

What is Knockout?

Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model (MVVM). Any time you have sections of UI that update dynamically (e.g., changing depending on the user’s actions or when an external data source changes), KO can help you implement it more simply and maintainable. You can find the more details here.

How knockout is differ from others?

I have developed two online examples to help understand Knockout better.

· Without Knockout – In this example, you just try to change the first name and last name instead of “Sivarajan” and “Raju” but still the full name will be “Sivarajan Raju”

· With Knockout – Here you can try to change the first name or last name, the full name will be changed automatically.

Since Knockout has been developed using Observer Pattern, whenever we make the changes in JavaScript object, the respective UI element will be refreshed automatically, likewise while changing the values in UI element (textbox, checkbox, etc..), the respective object will be updated.

Now we will walkthrough the steps involved in developing Status Update web part using Knockout and please note that this is not a complete implementation for Task management. Figure below depicts the final output of the web part.

clip_image002

Step 1:

Create the custom list “Tasks” with the following fields and fill the sample data.

1. Task (Single line of text)

2. Estimated Effort

3. Actual Effort

clip_image004

Step 2:

1. Create a new “SharePoint 2013 – Empty Project”.

2. Fill the local SharePoint site URL and then select the SharePoint Farm Solutions option.

3. Add the visual web part.

4. Download and refer the “jQuery” and “Knockout” libraries.

5. The solution structure will be like below.

clip_image005

Step 3:

We are going to add the following functionalities in the TaskManager.js

1. Create the jQuery load function

$(function () {

		//TODO: Add the complete functionalities of TaskManager.js here.

		});

2. Create the namespace to encapsulate the complete implementation.

var my = {};

3. Create the “Task” data model with “TaskName”, “EstimatedEffort” members.

 //Task model
		 my.Task = function () {
		     this.taskName = ko.observable();
		     this.estimatedEffort = ko.observable();
		 };

4. Create a “LineItem” entity with “Instance of the Task item”, “Actual Effort”, “Effort Diff” members.

 //Line item model
		 my.LineItem = function () {
		     var self = this;
		     self.task = ko.observable();
		     self.actualEffort = ko.observable(0);
		     self.effortDiff = ko.computed(function () {
		 	return self.task() ? (self.actualEffort() - self.task().estimatedEffort()) : 0;
		     });
		 };

5. Create the view model with the following members

tasks – Available Tasks

lines – User selected task items

addLine (function) – to add a new task line item

removeLine (function) – to add a remove an item from a line items

loadItems (function) – to load the available tasks from SharePoint list.

totalEffort (function) – This function will be triggered and total effort will be updated, while add or remove the line item by user.

 my.viewModel = function () {
		         var tasks = ko.observableArray([]),
		             lines = ko.observableArray([new my.LineItem()]),
		 
		             addLine = function () {
		                 lines.push(new my.LineItem());
		             },
		 
		             removeLine = function (line) {
		                 lines.remove(line);
		             },
		 
		             loadItems = function () {
		                 $.ajax({
		                     url: '/_vti_bin/listdata.svc/Tasks?$select=Task,EstimatedEffort,ActualEffort',
		                     type: 'GET',
		                     dataType: 'json',
		                     success: function (data) {
		 
		                         data.d.results.forEach(function (p) {
		                             tasks.push(new my.Task()
		                                     .taskName(p.Task)
		                                     .estimatedEffort(p.EstimatedEffort)
		                                 );
		                         });
		                     },
		                     error: function (errorText) {
		                         alert("error :" + errorText);
		                     }
		                 });
		             },
		 
		 
		             totalEffort = ko.computed(function () {
		                 var total = 0;
		                 var x = this;
		 
		                 $.each(lines(), function () {
		                     total += parseInt(this.actualEffort());
		                 });
		 
		                 return total;
		 
		             });
		 
		         return {
		             tasks: tasks,
		             lines: lines,
		             addLine: addLine,
		             removeLine: removeLine,
		             loadItems: loadItems,
		             totalEffort: totalEffort
		         }
		     }(); //Auto initialization
		 
		 my.viewModel.loadItems();

6. Apply the view model to UI elements.

ko.applyBindings(my.viewModel);

Step 4:

1. Open the “TaskManager.ascx” and add the following code

<SharePoint:ScriptLink ID="Scriptlink8" runat="server" Name="~Site/_layouts/15/SharePointKnockoutJS/Scripts/jquery-1.8.3.js"></SharePoint:ScriptLink>
		<SharePoint:ScriptLink ID="Scriptlink1" runat="server" Name="~Site/_layouts/15/SharePointKnockoutJS/Scripts/knockout-2.2.0.js"></SharePoint:ScriptLink>
		<SharePoint:ScriptLink ID="Scriptlink2" runat="server" Name="~Site/_layouts/15/SharePointKnockoutJS/Scripts/TaskManager.js"></SharePoint:ScriptLink>

2. Construct the Task header section here.

 <table border="1">
		         <thead>
		             <tr>
		                 <th>Task</th>
		                 <th>Estimated Effort</th>
		                 <th>Actual Effort</th>
		                 <th>Effort Difference</th>
		                 <th></th>
		             </tr>
		         </thead>

3. Construct the task details section here.

     <tbody data-bind="foreach: lines" >
		     <tr >
		         <td style="width: 25px;" >
		             <select data-bind="options:$parent.tasks, value:task, optionsText: 'taskName', optionsCaption:'Select a Task'">
		             </select>
		         </td>
		         <td style="width: 100px;" data-bind="if: task">
		             <span data-bind="text: task().estimatedEffort"></span>
		         </td>
		         <td style="width: 100px;text-align:right;" data-bind="if: task">
		             <input data-bind="value: actualEffort,valueUpdate: 'afterkeydown'" style="text-align:right;width:50px;" />
		         </td>
		         <td style="width: 100px;" data-bind="if: task">
		             <span data-bind="visible: task, text: effortDiff"></span>
		         </td>
		         <td style="width: 100px;">
		             <a href='#' data-bind="click: $parent.removeLine">Remove</a>
		         </td>
		     </tr>
		     </tbody>
		 </table>

4. Add the code to display “Total Efforts” and “No of Tasks”

Total Efforts : <span data-bind="text: totalEffort"></span>

<br />

No of Task(s) : <span data-bind="text: lines().length"></span>

<br />

<br />

5. Add the code for “Add New” task button

<button data-bind="click: addLine">New Task</button>

Conclusion

1. Here we have not added any code behind code and completely we have done using JavaScript and ListData.svc service.

2. The same approve we can use for SharePoint 2013 NAPA app development.

3. Normally the client side DOM manipulation (add or remove table rows), we have to write a lot of JavaScript code earlier using jQuery or JavaScript. But here we will work with JavaScript Object not a DOM elements.

4. Here we never referred any DOM elements inside the javascript and the “TaskManger.js” will have only the complete business logic.

5. Here Knockout will take care the responsibility of binding and collecting the object from the DOM elements.

6. In the next series, I will explain that how to maintain browser history and page navigation using Sammy.js library

Download Source

Author Info

Sivarajan Raju
 
SharePoint Consultant
 
Rate this article
 
Sivarajan 8 Plus years of experience in providing end-to-end solutions in the area of Web Technologies using Microsoft SharePoint 2010/2007, .NET Implemented several large-scale SharePoint portal solutions. Vast experience in ...read more
 

Leave a comment