65.9K
CodeProject is changing. Read more.
Home

Using Knockout.js for SharePoint Web Part Templating: Part 1

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (4 votes)

Dec 29, 2013

CPOL

4 min read

viewsIcon

26065

downloadIcon

222

How to template web parts with Knockout.js framework

Introduction

This topic came up when we got a request to create generic list and library web parts, that would display few common fields like ID, Title, Description, File Url etc. Prior to this request we solved similar issues with OOB list and library web parts with custom XSLT, by creating Visual Studio web part for branding purposes only, or by using Imtech content query web part( which is XSLT solution by design).

At the end, clients hated XSLT solutions and we hated to create new web part for every new list or library. That's where Knockout popped. Why don’t we use Knockout for templates instead XSLT.

I’ll assume that whoever reads this article knows about creating a web part for SharePoint, SharePoint module, java script and html and I will not go into details.

Background

A bit about Knockout

From Knockout web site: “Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model. “

From Wikipedia:

Knockout is a standalone JavaScript implementation of the Model-View-ViewModel pattern with templates. The underlying principles are therefore:

  • a clear separation between domain data, view components and data to be displayed
  • the presence of a clearly defined layer of specialized code to manage the relationships between the view components

Knockout includes the following features:

  • Declarative bindings
  • Automatic UI refresh (when the data model's state changes, the UI updates automatically)
  • Dependency tracking
  • Templating (using a native template engine although other templating engines can be used, such as jquery.tmpl)

So what’s the deal?

First you have your view model:

 var myViewModel = {
     personName: 'Bob',
     personAge: 123
};  

  Then you have a view: 

The name is <span data-bind="text:personName"></span>

At the end just bind your view to model

 ko.applyBindings(myViewModel); 

We'll talk about model later.

Using the code

Proof of concept

I've created an html mock of our web part. This is useful, because we can prepare java scripts, css files, models and views in advance and test it without SharePoint and visual studio.

You can download proof of concept as separate download from the link above.

References

There would be only two file references. 

One is knockout library itself 

<script type='text/javascript' src="http://knockoutjs.com/downloads/knockout-3.0.0.js"></script>  

and the other is css file I’ve added to this project

<link href="css/controls.css" rel="stylesheet" type="text/css" /> 

Model 

I've designed model as Item class. Here it is: 

// Item class definition
var Item = function (id, title, datecreated,url,description,thumbnail) {
   this.id = id;
   this.title = title;
   this.datecreated = datecreated;
   this.url=url;
   this.description=description;
   this.thumbnail=thumbnail;
} 

It’s called item and it has 6 properties:

  1. id - ID of the item
  2. title - Title of the item
  3. datecreated - Creation date of the item
  4. url - Url of the item
  5. description - Description of the item
  6. thumbnail - Thumbnail of the item

View model

Here is the view model

function viewModel1 (){
    var self = this;
    self.items =  [  
     new Item(2, 'News1 title','21.10.2013','javascript:OpenDialog(2);'
               ,'Description News 1','img/pic1.jpg'), 
    new Item(1, 'News 2 title','21.02.2013','javascript:OpenDialog(1);',
               'Description News 2','img/pic2.jpg')
}  

View model has property items, which in fact is collection of Item objects. For mocking purposes we’ve added two Item objects in this collection (News 1 and News 2);

View

Here is the view:
<div class="glwp glwp-central" id="k1">
  <div class="glwpLine"></div>
  <h5><img src="PublishingImages/siteIcon.png" 
          width="28" height="28" align="absmiddle" />
      News</h5>
  <div class="glwpLineGrey"></div>
    <ul data-bind="foreach:items">
      <li>
       <div class="glwpDate"><span data-bind="text: datecreated" ></span>
       <img class="glwpImage" data-bind="attr: { src: thumbnail }" />         
       </div>
       <div class="glwpText glwpText-central" >
        <a data-bind="attr: { href: url, title: title }" style="min-height:70px;">
         <span class="glwpTextTTL" data-bind="text:title"></span><br />
         <span data-bind="text: description"></span>
        </a>
       </div>
       <div class="glwpSep"></div>
      </li>
    </ul>
</div>  

What we have here:

     It’s pretty simple. We have unordered list bound to our model. One <li> element would be created for every item of our items collection (data-bind="foreach: items”). 

Property binding: 

  •  <span data-bind="text: datecreated" ></span> - This is the simplest data binding. It would write datecreated property of Item object to text of span element (like: <span>11/11/2013</span>)
  • <img class="glwpImage" data-bind="attr: { src: thumbnail }" />. This is a bit more complicated binding. It would take thumbnail property of item object and write it to src attribute of img element.
  • <a data-bind="attr: { href: url, title: title }" style="min-height:70px;">. It would take url property and write it as href attribute of the a element, and title property as title attribute.
  • <span class="glwpTextTTL" data-bind="text:title"></span>. Title property would be written as text of span element 
  • <span data-bind="text: description"></span>. Description property would be written as text of span element

So anyone with little knowledge of html and css can customize this template anyway (s)he likes, as long as (s)he provides required properties. 

Binding

ko.applyBindings(viewModel1,document.getElementById('k1'));

Note second parameter in applyBindings method. It says document.getElementById('k1'). Same id is on the first div in our view (<div class="glwp glwp-central" id="k1">). This is helpful if you want to have more than one view model in one page. It tells knockout to bind this specific model (viewModel1) to specific template on our page (k1).

What we have from this? We are going to create web part from this code and one of the web part features is that you can put same web part several times on the same page. So it would be possible to put one web part in SharePoint page to display news and one web part to display projects or documents. And they will coexist together.

If you look at the source you will notice that we have 2 view models (viewModel1 and viewModel2) and two templates (k1 and k2), and two bindings of course. One binding is for news (with images and description) and one binding is for files (no images, and no descriptions). Templates are slightly different.

Final result

Here is the final result 


What next? 

You can download (Download ProofOfConcept.zip) ProofOfConcept.zip play a little with it and then move to Part 2 of this series.