Ashok Raja's Blog
KnockoutJs Data binding in SharePoint 2013 with jQuery, SPServices and DataJs
by Ashok Raja T 27. June 2013 06:20

In this article we can see how to bind the SharePoint 2013 List Items retrieved via popular Java script frameworks like jQuery, SPServices , DataJs with KnockoutJs. To query the SharePoint list, I’ll be using CAML query for SPServices and oData query for jQuery and DataJs.

Prerequisites

These samples are based on a SharePoint List named “Employees” having columns Title and City with some records.

Download Knockout Js, jQuery, DataJs, SpServices and Knockout Wrap Extension (can also be downloaded from the bottom of the post along with the samples) and add it to the Page or the WebPart. For referring script, you can either use SFS Script Box or follow the conventional methods explained here.

The next step is to create a view modal.

Knockout Js and jQuery ( Json Request )

Knockout View Modal

The below knockout view modal performs a ajax request to the SharePoint 2013 Rest API and binds the data to a knockout observable array.

 <script type="text/javascript">
     function Employee(data) {
         this.Id = ko.observable(data.Id);
         this.Title = ko.observable(data.Title);
         this.City = ko.observable(data.City);
     }
 
     function EmployeeModal() {
         var self = this;
         self.Employees = ko.observableArray([]);
         $.getJSON(_spPageContextInfo.webAbsoluteUrl + "/_vti_bin/listdata.svc/Employees?$top=2",
              function (data) {
                  if (data.d) {
                      if (data.d.results)
                          $.each(data.d.results, function (k, l) { self.Employees.push(new Employee({ Id: l.Id, Title: l.Title, City: l.City })) });
                      else
                          $.each(data.d, function (k, l) { self.Employees.push(new Employee({ Id: l.Id, Title: l.Title, City: l.City })) });
                  }
              }
         );
     }
     ko.applyBindings(new EmployeeModal());
 </script>

In the above code, object mapping is explicitly performed for each columns and data is pushed to "Employees" array. Instead , we can also use knockout wrapping extension to perform this data mapping.

The below code uses knockout wrapping extension for mapping json objects to Javascript objects. This method also eliminates the explicit creation of Employee object

Data Mapping with Knockout Wrap Extension

 <script type="text/javascript">
     function EmployeeModal() {
         var self = this;
         self.Employees = ko.observableArray([]);
         $.getJSON(_spPageContextInfo.webAbsoluteUrl + "/_vti_bin/listdata.svc/Employees?$top=2",
              function (data) {
                  if (data.d) {
                      if (data.d.results)
                          self.Employees(ko.wrap.toJS(data.d.results));
                      else
                          self.Employees(ko.wrap.toJS(data.d));
                  }
              }
         );
     }
     ko.applyBindings(new EmployeeModal());
 </script>
Note : The data objects returned by getJSON method differs based on oData query used to query the SharePoint Rest API. If the query contains “top” filter, then list items can be accessed directly from the root object “d”, else the list items are available under “d.results” object.

View

The below is the HTML markup used as view for the above View Modal

 <h3>All Employees</h3>
 <br />
 <table>
     <thead>
         <tr>
             <th>Id</th>
             <th>Employee Name</th>
             <th>City</th>
         </tr>
     </thead>
     <tbody data-bind="foreach:Employees">
         <tr>
             <td data-bind="text:Id"></td>
             <td data-bind="text:Title"></td>
             <td data-bind="text:City"></td>
         </tr>
     </tbody>
 </table>

Out Put

Employees

Note: The HTML part is common for all the binding methods explained below. Only the View Modal has been changed for each approach.

Knockout Js  and jQuery ( Ajax Request )

View Modal

 <script type="text/javascript">
     function EmployeeModal() {
         var self = this;
         self.Employees = ko.observableArray([]);
         jQuery.ajax({
             url: _spPageContextInfo.webAbsoluteUrl + "/_vti_bin/listdata.svc/Employees?$top=2",
             type: "GET",
             async: false,
             headers: { "Accept": "application/json;odata=verbose" },
             success: function (data) {
                 if (data.d) {
                     if (data.d.results)
                         self.Employees(ko.wrap.toJS(data.d.results));
                     else
                         self.Employees(ko.wrap.toJS(data.d));
                 }
             }
         });
     }
     ko.applyBindings(new EmployeeModal());
 </script>

Knockout Js and SPServices

View Modal

 <script type="text/javascript">
     function EmployeeModal() {
         var self = this;
         self.Employees = ko.observableArray([]);
         $().SPServices({
             operation: "GetListItems",
             async: false,
             listName: "Employees",
             CAMLQuery: "<Query></Query>",
             completefunc: function (xData, Status) {
                 var jData = $(xData.responseXML).SPFilterNode("z:row").SPXmlToJson({ includeAllAttrs: true, removeOws: true });
                 self.Employees(ko.wrap.toJS(jData));
             }
         });
     }
     ko.applyBindings(new EmployeeModal());
 </script>
Note: SPServices uses Lists.asmx web service to retrive data from a SharePoint list. This service (not the problem of SPservices) has a peculiar behaviour of skipping items with null values in the rendered output result. So this will cause error while binding data in Knockout if the mapped column is not available.
Note : In the SOAP XML returned by Lists.asmx, ID column of SharePoint List is reffered as "ID" (All Caps), but oData query returns "ID" column as "Id" .So, change the line "<td data-bind="text:Id"></td>" to "<td data-bind="text:ID"></td>" in HTML View .

SharePoint List Data with Knockout Js and DataJs

View Modal

 <script type="text/javascript">
     function EmployeeModal() {
         var self = this;
         self.Employees = ko.observableArray([]);
         OData.read(_spPageContextInfo.webAbsoluteUrl + "/_vti_bin/listdata.svc/Employees?$top=2",
                   function (data) {
                       self.Employees(ko.wrap.toJS(data.results));
                   });
     }
     ko.applyBindings(new EmployeeModal());
 </script>
Note : Unlike jQuery , objects are always accessible at "data.results" even if the filter keyword "top" is used in query.
Note : In the subsequent posts , we can see how to handle data binding in Knockout with complex data like lookup, multi-select lookups and user id. To know more about oData query and SharePoint 2013 REST API , check my earlier article here

Download Source Code

blog comments powered by Disqus