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:
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:
- id - ID of the item
- title - Title of the item
- datecreated - Creation date of the item
- url - Url of the item
- description - Description of the item
- 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.