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.
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
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.
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
Leave a comment