Today I have released KoSp (Knockout for SharePoint) in codeplex. If you love client side scripting in SharePoint 2013 or SharePoint 2010 with Rest API or SP services, then this is for you. KoSp provides a set of knockout binding handlers for SharePoint list data that can be bound directly to client side html controls like any other default knockout binder.
Json data from SharePoint Rest API via oData queries or data from SPservices based on CAML queries could be quiet complex depending on the data type of SharePoint list columns. Some of the complex SharePoint Field Types like lookups, choices, users and multi-select variants of these columns are represented as nested json objects which also requires further parsing of data depending on the data type of the respective SharePoint field. KoSp leverages the binding capabilities of knockout by providing additional custom knockout binding handlers specifically targeted towards json data from SharePoint lists.
Date Time parsing and Number formatting is one of the key challenges that every one encounters while handling json data. KoSp uses moment js and numeral js to handle parsing and formatting of dates and numbers instead of re-inventing the wheel .
KoSp is released in 2 variants in Code Plex. One is the usual minified version ( ko.sp-[Version Number].min.js) and the other is a minified version with embedded minified version of moment.js and numerals.js (ko.sp-[Version Number].min.Ex.js) . If you have already referred Moment Js and Numeral Js in your SharePoint page , then use ko.sp-[Version Number].min.js variant instead of ko.sp-[Version Number].min.Ex.js
Pre-requisites
The below JavaScript libraries are pre-requisites for KoSp
1. Knockout Js ( Tested with Version 2.3 and 3.0 Beta)
2. jQuery ( For REST API calls )
3. Moment JS ( For Date Time parsing and formatting, bundled with ko.sp-[Version Number].min.Ex.js)
4. Numerals JS ( For Number formatting, bundled with ko.sp-[Version Number].min.Ex.js)
5. SP Services – Optional, its required only if you wish to perform data requests via lists.asmx with CAML queries instead of oData queries with REST API
Project Home in codeplex http://kosp.codeplex.com
The below is the screen shot of SharePoint list data bound to client side html controls with knockout and KoSp.
This list contains all the data types supported by SharePoint Rest API. The below screenshot shows the field names and their data types.
Default View properties screen of a record
SharePoint Field Types and its representation
Index | Label Name | Field Type | Remarks |
0 | Keywords | Choice | Multi- Select |
1 | Sample Content | Attachments | Multi – Items |
2 | Technology | Lookup | Multi-select |
3 | Authors | People/Group | Multi-Select |
4 | Release Date | Date Time | Formatted Text |
5 | Level | Lookup | Single Selection |
6 | Download Book | Hyperlink | URL link |
7 | Availability | Choice | Single Selection |
8 | Price – Original Price | Currency | With Decimal Value |
8 | Price- Discount | Number | With Decimal Value |
8 | Price- Discounted Price | Calculated Field | Price – Discount |
9 | Is Active | Yes / No | Formatted Text |
Last updated on | Date Time | Formatted Text | |
Last Updated By | People/Group | Single User | |
(Book Image) | Hyperlink | URL of an Image | |
(Title) | Single Line of text | Default text binding | |
(Description) | Rich Text | Default html binding |
KoSp binding for the above screenshot based on REST API
Label Name | KoSP binding for REST API |
Keywords | data-bind=”spChoice:Keywords,multi:true” |
Sample Content | data-bind=”spUrl:Attachments,multi:true, dataFormat:’ <br/>'” |
Technology | data-bind=”spLookup:Technology,multi:true,dataFormat:’ <br/>'” |
Authors | data-bind=”spUser:Authors,multi:true,dataFormat:’ <br/>'” |
Release Date | data-bind=”spDate:ReleaseDate” |
Level | data-bind=”spLookup:Level” |
Download Book | data-bind=”spHref:DownloadURL,displayText:’Download Book'” |
Availability | data-bind=”spChoice:Availability” |
Price – Original Price | data-bind=”spNumber:Price,dataFormat:’$ 0,0.00′” |
Price- Discount | data-bind=”spNumber:DiscountPercentage,dataFormat:’0 %’,defaultValue:’N.A'” |
Price- Discounted Price | data-bind=”spNumber:SellingPrice,dataFormat:’$ 0,0.00′” |
Is Active | data-bind=”spBool:IsActive” |
Last updated on | data-bind=”spDate:Modified,dataFormat:’DD-MMM-YYYY, hh:mm:ss a'” |
Last Updated By | data-bind=”spUser:ModifiedBy” |
Book Image | data-bind=”spSrc:CoverPhoto” |
Title | data-bind=”text:Title” |
Description | data-bind=”html:AboutTheBook” |
KoSp binding for the above screenshot based on SP Services
Label Name | KoSP binding for data via SP Services |
Keywords | data-bind=”spChoice:Keywords,src:’sps'” |
Sample Content | data-bind=”spUrl:Attachments,src:’sps’, dataFormat:’ <br/>'” |
Technology | data-bind=”spLookup:Technology,,src:’sps’,dataFormat:’ <br/>'” |
Authors | data-bind=”spUser:Authors,src:’sps’,dataFormat:’ <br/>'” |
Release Date | data-bind=”spDate:ReleaseDate,src:’sps'” |
Level | data-bind=”spLookup:Level,src:’sps'” |
Download Book | data-bind=”spHref:DownloadURL,displayText:’Download Book'” |
Availability | data-bind=”spChoice:Availability,src:’sps'” |
Price – Original Price | data-bind=”spNumber:Price,src:’sps’,dataFormat:’$ 0,0.00′” |
Price- Discount | data-bind=”spNumber:DiscountPercentage,src:’sps’,dataFormat:’0 %’,defaultValue:’N.A'” |
Price- Discounted Price | data-bind=”spNumber:SellingPrice,src:’sps’,dataFormat:’$ 0,0.00′” |
Is Active | data-bind=”spBool:IsActive,src:’sps'” |
Last updated on | data-bind=”spDate:Modified,src:’sps’,dataFormat:’DD-MMM-YYYY, hh:mm:ss a'” |
Last Updated By | data-bind=”spUser:ModifiedBy,src:’sps'” |
Book Image | data-bind=”spSrc:CoverPhoto” |
Title | data-bind=”text:Title” |
Description | data-bind=”html:AboutTheBook” |
Knockout View and View Modal based on Rest API
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/knockout-3.0.0beta.js"></script>
<script src="js/ko.sp-1.0.min.Ex.js"></script>
<link href="css/books.css" rel="stylesheet" />
<div data-bind="template: { name: 'allBooks-template', foreach: Books }"></div>
<script type="text/html" id="allBooks-template">
<div class="bookItem">
<div class="bookImg">
<img width="200px" height="110px" data-bind="spSrc:CoverPhoto" />
</div>
<div class="bookContent">
<div class="bookTitle" data-bind="text:Title"></div>
<div class="bookDesc" data-bind="html:AboutTheBook"></div>
<span><b>Keywords</b></span>
<div data-bind="spChoice:Keywords,multi:true"></div>
<span><b>Sample Content</b></span>
<div data-bind="spUrl:Attachments,multi:true, dataFormat:'<br/>'"></div>
</div>
<div class="bookDetails">
<div>
<div><b>Technology</b></div>
<span data-bind="spLookup:Technology,multi:true,dataFormat:'<br/>'"></span>
</div>
<div>
<div><b>Author(s)</b></div>
<span data-bind="spUser:Authors,multi:true,dataFormat:'<br/>'"></span>
</div>
<div>
<div><b>Release Date</b></div>
<span data-bind="spDate:ReleaseDate"></span>
</div>
<div>
<div><b>Level</b></div>
<span data-bind="spLookup:Level"></span>
</div>
<div>
<a href="#" data-bind="spHref:DownloadURL,displayText:'Download Book'"></a>
</div>
</div>
<div class="bookDetails">
<div>
<div><b>Availability</b></div>
<span data-bind="spChoice:Availability"></span>
</div>
<div>
<div><b>Price</b></div>
Original Price <b><span data-bind="spNumber:Price,dataFormat:'$ 0,0.00'"></span></b>
<br />
Discount <b><span data-bind="spNumber:DiscountPercentage,dataFormat:'0 %',defaultValue:'N.A'"></span></b>
<br />
Discounted Price <b><span data-bind="spNumber:SellingPrice,dataFormat:'$ 0,0.00'"></span></b>
</div>
<div>
<div><b>Last updated on</b></div>
<span data-bind="spDate:Modified,dataFormat:'DD-MMM-YYYY, hh:mm:ss a'"></span>
</div>
<div>
<div><b>Last updated By</b></div>
<span data-bind="spUser:ModifiedBy"></span>
</div>
<div>
<div><b>Is Active</b></div>
<span data-bind="spBool:IsActive"></span>
</div>
</div>
<div style="clear: both"></div>
</div>
</script>
<script type="text/javascript">
function BookModal() {
var self = this;
self.Books = ko.observableArray([]);
$.getJSON(_spPageContextInfo.webAbsoluteUrl + "/_vti_bin/listdata.svc/Books?$expand=Level,Technology,Keywords,Availability,Authors,Attachments,ModifiedBy&$select=Title,Level/Title,Technology/Title,AboutTheBook,Keywords/Value,CoverPhoto,Attachments,Authors/Name,ReleaseDate,DownloadURL,Availability,Price,DiscountPercentage,SellingPrice,Modified,ModifiedBy/Name,IsActive",
function (data) {
if (data.d.results) {
self.Books(ko.toJS(data.d.results));
}
}
);
}
ko.applyBindings(new BookModal());
</script>
Knockout View and View Modal based on SP Services
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/jquery.SPServices-2013.01.min.js"></script>
<script src="js/knockout-3.0.0beta.js"></script>
<script src="js/ko.sp-1.0.min.Ex.js"></script>
<link href="css/books.css" rel="stylesheet" />
<div data-bind="template: { name: 'allBooks-template', foreach: Books }"></div>
<script type="text/html" id="allBooks-template">
<div class="bookItem">
<div class="bookImg">
<img width="200px" height="110px" data-bind="spSrc:CoverPhoto" />
</div>
<div class="bookContent">
<div class="bookTitle" data-bind="text:Title"></div>
<div class="bookDesc" data-bind="html:AboutTheBook"></div>
<span><b>Keywords</b></span>
<div data-bind="spChoice:Keywords,src:'sps'"></div>
<span><b>Sample Content</b></span>
<div data-bind="spUrl:Attachments,src:'sps'"></div>
</div>
<div class="bookDetails">
<div>
<div><b>Technology</b></div>
<span data-bind="spLookup:Technology,src:'sps',dataFormat:'<br/>'"></span>
</div>
<div>
<div><b>Author(s)</b></div>
<span data-bind="spUser:Authors,src:'sps',dataFormat:'<br/>'"></span>
</div>
<div>
<div><b>Release Date</b></div>
<span data-bind="spDate:ReleaseDate,src:'sps'"></span>
</div>
<div>
<div><b>Level</b></div>
<span data-bind="spLookup:Level,src:'sps'"></span>
</div>
<div>
<a href="#" data-bind="spHref:DownloadURL,displayText:'Download Book'"></a>
</div>
</div>
<div class="bookDetails">
<div>
<div><b>Availability</b></div>
<span data-bind="spChoice:Availability,src:'sps'"></span>
</div>
<div>
<div><b>Price</b></div>
Original Price <b><span data-bind="spNumber:Price,src:'sps',dataFormat:'$ 0,0.00'"></span></b>
<br />
Discount <b><span data-bind="spNumber:DiscountPercentage,src:'sps',dataFormat:'0 %',defaultValue:'N.A'"></span></b>
<br />
Discounted Price <b><span data-bind="spNumber:SellingPrice,src:'sps',dataFormat:'$ 0,0.00'"></span></b>
</div>
<div>
<div><b>Last updated on</b></div>
<span data-bind="spDate:Modified,src:'sps',dataFormat:'DD-MMM-YYYY, hh:mm:ss a'"></span>
</div>
<div>
<div><b>Last updated By</b></div>
<span data-bind="spUser:ModifiedBy,src:'sps'"></span>
</div>
<div>
<div><b>Is Active</b></div>
<span data-bind="spBool:IsActive,src:'sps'"></span>
</div>
</div>
<div style="clear: both"></div>
</div>
</script>
<script type="text/javascript">
function Book(data) {
this.Title = ko.observable(data.Title);
this.Level = ko.observable(data.Level);
this.Technology = ko.observable(data.Technology);
this.AboutTheBook = ko.observable(data.AboutTheBook);
this.Keywords = ko.observable(data.Keywords);
this.Availability = ko.observable(data.Availability);
this.ReleaseDate = ko.observable(data.ReleaseDate);
this.Price = ko.observable(data.Price);
this.DiscountPercentage = ko.observable(data.DiscountPercentage);
this.SellingPrice = ko.observable(data.SellingPrice);
this.CoverPhoto = ko.observable(data.CoverPhoto);
this.DownloadURL = ko.observable(data.DownloadURL);
this.AvailableQuantity = ko.observable(data.AvailableQuantity);
this.Authors = ko.observable(data.Authors);
this.IsActive = ko.observable(data.IsActive);
this.Modified = ko.observable(data.Modified);
this.ModifiedBy = ko.observable(data.ModifiedBy);
this.Attachments = ko.observable(data.Attachments);
}
function BooksModal() {
var self = this;
self.Books = ko.observableArray([]);
$().SPServices({
operation: "GetListItems",
async: false,
listName: "Books",
CAMLQueryOptions: "<QueryOptions><IncludeAttachmentUrls>True</IncludeAttachmentUrls></QueryOptions>",
CAMLViewFields: "<ViewFields Properties='True' />",
CAMLQuery: "<Query></Query>",
completefunc: function (xData, Status) {
var spsData = $(xData.responseXML).SPFilterNode("z:row").SPXmlToJson({ includeAllAttrs: true, removeOws: true });
if (spsData) {
$.each(spsData, function (k, l) {
self.Books.push(new Book({
Title: l.Title,
Level: l.Level,
Technology: l.Technology,
AboutTheBook: l.About_x0020_The_x0020_Book,
Keywords: l.Keywords,
Availability: l.Availability,
ReleaseDate: l.Release_x0020_Date,
Price: l.Price,
DiscountPercentage: l.Discount_x0020_Percentage,
SellingPrice: l.Selling_x0020_Price,
CoverPhoto: l.Cover_x0020_Photo,
DownloadURL: l.Download_x0020_URL,
AvailableQuantity: l.Available_x0020_Quantity,
Authors: l.Authors,
IsActive: l.Is_x0020_Active,
Modified: l.Modified,
ModifiedBy: l.Editor,
Attachments: l.Attachments
}))
});
}
}
});
}
ko.applyBindings(new BooksModal());
</script>
Articles on Knockout For SharePoint (KoSp) Series
Sl.No | Article |
1 | Introducing KoSpJs – Knockout binding handlers for SharePoint REST API and SPServices – This Article |
2 | Beginning SharePoint development with KoSpJs, REST API and SP Services |
3 | SharePoint Lookup fields, Choice Fields and it’s multi select variants in KoSpJs |
4 | Formatting Date, Number Fields in SharePoint REST API and SPServices with KoSpJs |
5 | Binding Hyperlink and Image URLs with KoSpJs in SharePoint REST API and SPServices |
6 | Retrieving and binding User and User Group Details in SharePoint REST API with KoSpJs |
Leave a comment