Knockout.js with Sharepoint 2013 App – Part I

Knockout.js is an amazing javascript library for binding data and generating html at run time. It uses MVVM pattern that is Model-View-ViewModel pattern. This post assumes that you have a basic understanding of knockout and sharepoint client side object model. If not, then go through the amazing set of tutorials present in knockout (KO) site.

I was recently introduced to KO and found it amazing. But I didn’t find much on how to implement it in sharepoint context. So, I decided to look into it and  share with you all my learnings of KO with sharepoint. This post is dedicated to just displaying data from a list in a page using KO. Further posts will focus on adding and removing data too. At the end, we will see if KO is actually a good option for sharepoint or not. The post in the series will be:

  1. Part I – Displaying Data from SP list. (this one)
  2. Part II – Adding Data to SP list.
  3. Part III – Removing Data from SP list.

To start I am using sharepoint 2013 app model. A sharepoint hosted app is created for displaying list’s data in html page present in app context. The structure of the list is:

List for knockout Demo

This is a simple list which contains names of country and their states. Using KO we will display this in a table structure. KO makes the client side code simple and easier to use. HTML, CSS and JS all files are separate and manageable.

So the code for displaying this data is :


.tableStyle {
border-collapse:collapse;
border: 1px solid black;
text-align:center;
width:50%;
padding:15px;
}

view raw

App.css

hosted with ❤ by GitHub


'use strict';
var hostWebUrl;
var appWebUrl;
var listItems
var completeCountryList;
$(document).ready(function () {
//get the url of app web and host web
hostWebUrl = QS("SPHostUrl");
appWebUrl = QS("SPAppWebUrl");
LoadData();
});
//class for saving the countries and their states
function CountryList(countryName, stateName) {
var self = this;
self.CountryName = countryName;
self.StateName = stateName;
}
//View Model to combine data from list into the format which view expects
function CountryListViewModel() {
var self = this;
self.Countries = ko.observableArray([]);
self.AddCountries = function (countryName, stateName) {
self.Countries.push(new CountryList(countryName, stateName));
}
}
//function which apply KO bindings and make a call to SP using CSOM
function LoadData() {
completeCountryList = new CountryListViewModel();
GetList();
ko.applyBindings(completeCountryList);
}
function GetList() {
var context = new SP.ClientContext(appWebUrl);
//No need to use SP.RequestExecutor.js for cross domain calls to host web in SP Hosted web
/* var factory = new SP.ProxyWebRequestExecutorFactory(appWebUrl);
context.set_webRequestExecutorFactory(factory); */
var hostContext = new SP.AppContextSite(context, hostWebUrl);
var list = hostContext.get_web().get_lists().getByTitle("KnockoutList");
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<View><RowLimit>10</RowLimit></View>");
listItems = list.getItems(camlQuery);
context.load(listItems, "Include(Id, CountryName, StateName)");
context.executeQueryAsync(ListItemsLoaded, ListItemsFailed);
}
function ListItemsLoaded(sender, args) {
var enumerator = listItems.getEnumerator();
while (enumerator.moveNext()) {
var currentItem = enumerator.get_current();
completeCountryList.AddCountries(currentItem.get_item("CountryName"), currentItem.get_item("StateName"));
}
}
function ListItemsFailed(sender, args) {
alert(args.get_message());
}
function QS(name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

view raw

App.js

hosted with ❤ by GitHub


<asp:Content ContentPlaceHolderID="PlaceHolderMain" runat="server">
<div id="divCountryList">
<h2>Country List</h2>
<br />
<table id="tblCountryList" border="1" class="tableStyle">
<thead>
<tr>
<th>Country</th>
<th>State</th>
</tr>
</thead>
<!– Iterating through every list item using foreach of KO –>
<tbody data-bind="foreach: Countries">
<tr>
<td data-bind="text: CountryName"></td>
<td data-bind="text: StateName"></td>
</tr>
</tbody>
</table>
</div>
</asp:Content>

view raw

default.aspx

hosted with ❤ by GitHub

The output page will look like:

KO output 1

This is how we use KO in sharepoint. Notice the object oriented structure of “App.js”.  The code is relatively very clean and easy to understand. In next post we will add items in a list using KO. Hope this helps.

16 thoughts on “Knockout.js with Sharepoint 2013 App – Part I

  1. Hi Garima!
    This blog help me alot. Being new to SharePoint development, I am wondering if it is possible to get data from two or more sharepoint lists and display via sharepoint hosted app (trying to take advantage of ID), using JS knockout and caml query but still no success. I am working on a school project where i want to use SP list (that i developed via VisualStudio )like SQL database list or simply as data base and trying to display some info using SharePoint Apps in a single table.

  2. Hi. This is a great post, but the list doesn’t work for me. Can you please explain the following:
    1. which script libraries did you reference?
    2. can you please breakdown where you put each of the scripts (all in a single ‘script editor’? in 3 separate content editors?)
    3. Can you please break this process down step by step for the beginners?

    thank you a lot

  3. Thank you — the script worked great!

    The only setback was the date field on my script isn’t populating in knockout.

    field name: ArticleDate
    bind=”spDate:ArticleDate” <—this doesn't work

    I have been trying to figure it out and I have no idea why.

  4. Sorry i couldn’d understand
    10 hostWebUrl = QS(“SPHostUrl”);
    11 appWebUrl = QS(“SPAppWebUrl”);
    Can you show examle of SPHostUrl and SPAppWebUrl

    • Hi, So I used this example in a SP hosted app where you get SPHostUrl and SPAppWebUrl in query string (as parameters). I needed them to create SP context. If you are not using SP hosted app then you can safely skip this step. And if you are using app, you will get them in query string. Hope this helps.

Leave a reply to senstiveheart Cancel reply