Simple Databinding and Templating using Knockout and ASP.NET Web API

Posted by: Suprotim Agarwal , on 3/31/2013, in Category ASP.NET
Views: 242614
Abstract: This article demonstrates how Knockout takes client-side interactivity to a new level. Combined with ASP.NET Web API, it forms a nice Client-Server tango for creating rich and interactive web applications

Single Page Apps have been catching on and Microsoft’s latest Web Tool release puts it front and center with the default SPA template. The template uses KnockoutJS and Web API to build a fully functional note taking app.

However before we get into SPAs, a certain level of understanding of KnockoutJS is required. Today we’ll take a look at two fundamental pieces of KnockoutJS - Databinding and Templating. We’ll use a simple JavaScript ViewModel combined with the jQuery UI Tab control.

 

What is KnockoutJS?

Knockout (KO) is a JavaScript library that provides a way to do Declarative Bindings using an ‘Observable’ ViewModel on the client (browser), enabling UI to refresh itself automatically whenever the bound data, changes. Knockout also has its own templating engine that helps you bind data in collections et al rather effortlessly. KO also provides dependency tracking to help chain relationship among various objects in the View Model.

Getting Started with the Web API Backend

We will start our sample with a Web API MVC template instead of the SPA Template. This will help us look into the basics and give us the low-down on how KO works.

Step 1: Once the Solution is ready, we’ll rename the default ValuesController to BlogsController

web-api-template

Step 2: In the Models folder, we’ll add a class call Blog.cs. This class will serve as our Domain Model.

public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Post { get; set; }
public string Comments { get; set; }
}

Step 3: Next we update our BlogController API to work with the Blog Entry. We implement an in-memory list of Blogs and implement the Get, Put, Post and Delete methods appropriately.

public class BlogsController : ApiController
{
List<Blog> BlogContext;
public BlogsController()
{
  if (HttpContext.Current.Application["blogContext"] == null)
  {
   HttpContext.Current.Application["blogContext"] = new List<Blog>();
  }
  BlogContext = (List<Blog>)(HttpContext.Current.Application["blogContext"]);
}
// GET api/values
public IEnumerable<Blog> Get()
{
  return BlogContext;
}

// GET api/values/5
public Blog Get(int id)
{
  Blog current = BlogContext.Find(b => b.Id == id && !b.IsDeleted);
  if (current == null)
  {
   throw new HttpResponseException(HttpStatusCode.NotFound);
  }
  else
  {
   return current;
  }
}

// POST api/values
public void Post([FromBody]Blog value)
{
  value.Id = BlogContext.Count + 1;
  BlogContext.Add(value);
}

// PUT api/values/5
public void Put(int id, [FromBody]Blog value)
{
  Blog current = BlogContext.Find(b => b.Id == id);
  if (current == null || current.IsDeleted)
  {
   throw new HttpResponseException(HttpStatusCode.NotFound);
  }
  else
  {
   current.Title = value.Title;
   current.Post = value.Post;
   current.IsDeleted = value.IsDeleted;
  }
}

// DELETE api/values/5
public void Delete(int id)
{
  Blog current = BlogContext.Find(b => b.Id == id);
  if (current == null || current.IsDeleted)
  {
   throw new HttpResponseException(HttpStatusCode.NotFound);
  }
  else
  {
   current.IsDeleted = true;
  }
}
}

With the API controller done, we shift our focus to the View.

Building the Knockout ViewModel

Let’s say we want to build a blog management dashboard that supports editing of Multiple posts at the same time. Our UI is split into two

1. A List on the Left Hand Side with Add New, Edit and Delete buttons

2. An Edit pane on the right hand side that shows the selected Blog

3. We have a Save button that posts all the updated data back to the Server

The View Model

We start off with a simple ViewModel that has only one property and one behavior (code in ko-blog.js)

var viewModel =
{
blogs : ko.observableArray([]),
newBlog: function ()
{
  this.blogs.push({
   Title: ko.observable("New " + this.blogs().length),
   Id: ko.observable(this.blogs().length + 1),
   Post: ko.observable("Post " + this.blogs().length),
   IsNew: ko.observable(true),
   IsDeleted: ko.observable(false)
  });
}
}

In the ViewModel above, we have the blogs property. It’s of type ko.observable array, which means Knockout will refresh the UI when we add or remove items to the array.

To use the above ViewModel, we load the data as follows:

$(document).ready(function ()
{
$(".right-section").hide();
$.ajax(
{
  url: "/api/Blogs",
  contentType: "text/json",
  type: "GET",
  success: function (data)
  {
   $.each(data, function (index)
   {
    viewModel.blogs.push(toKoObserable(data[index]));
   });
  ko.applyBindings(viewModel);
},
error: function (data)
{
  alert("ERROR");
}
});

function toKoObserable(blog)
{
  return {
   Id: ko.observable(blog.Id),
   Title: ko.observable(blog.Title),
   Post: ko.observable(blog.Post),
   Comments: ko.observable(blog.Comments),
   IsDeleted: ko.observable(blog.IsDeleted)
  };
}
}

Basically on the document ready event, we query our Web API and get the list of Blog items. Once we receive the value, we covert it into a JavaScript object of observable properties.

Note: We could have used the JSON object directly and put it into the array, this would have refreshed any list that we bind to this view model. However later we’ll see why having each property as observable helps us out.

ViewModel Binding and Templating

In the Index.cshtml we bind the view model as follows:

<div id="body">
<div class="left-section" style="height: 600px; width: 25%; float: left; background-color: #b9b9b9">
  <h2>Blogs</h2>
  <button data-bind="click: newBlog">New Blog</button><button id="saveAll">Save</button>
  <ul data-bind="foreach: blogs">
   <li style="list-style: none">
    <a data-bind="text: Title, id: Id" href="#"></a>
   </li>
  </ul>
</div>
</div>

@section Scripts{
    <script src="~/Scripts/knockout-2.2.0.js"></script>
    <script src="~/Scripts/ko-blog.js"></script>
}

The first binding is to the button. We have used the data-bind attribute to tell KO that it should bind the click event of the button to the newBlog behavior method of the view model. So for every click, the above method is called. Next we have bound the array of blogs to the <ul> by using the ‘for-each’ syntax of KO.

Note: Inside a foreach the entire block is considered a template. So for each element in the blogs array one <li> will be generated.

The <li> has an anchor tag whose text attribute is bound to the Title property of each Blog. Now if we run the app and if you click the “New Blog” button, an item will get added to the List.

Two way Data Binding

So far we saw how data binding can be used for collections. Now let’s see how we can use it for properties to update values that we get from the server (and submit it back to the server). To do this, we’ll extend the view model a little

var viewModel =
{

selectedBlog: ko.observable(null),
selectBlog: function(blog)
{
  viewModel.selectedBlog(this);
  $(".right-section").show();
},

}

I’ve shown only the new property and behavior above. The selectedBlog property is a ko.observable object that’s initially set to null. The selectBlog method updates the selectedBlog property. We will shortly see how this is fired.

Once the blog is selected, we want the selected blog’s properties to be visible on the page (without postback). To do this, we update the Index.cshtml by adding the following div after the left-section.

<div class="right-section"
  style="height: 600px; width: 75%;
  float: left; background-color: #d9d9d9"
  data-bind="with: selectedBlog">
<div>
  Title:
  <input data-bind="value: Title" />
</div>
<div>
   Post:
  <textarea data-bind="value: Post" ></textarea>
</div>
</div>

Here we see another type of KO binding. The ‘right-section’ div is bound to selectedBlog using the ‘with’ syntax. This essentially means, anything inside the div will have the view model scope reduced to just the selectedBlog. Thus now we can bind an input box and a textarea to the Title and the Post properties respectively. These properties come from the ‘selectedBlog’.

Now to add a ‘Select’ button for every <li> in the Blog list.

<li style="list-style: none">

<input type="button" value="Select" data-bind="click: $parent.selectBlog" />
</li>

We add the above markup in the <li> template for the Blog list. We see we have bound the click event to the selectBlog method. However note that inside the loop, the scope of binding is each Blog object, not the full ViewModel (in which we defined the method). As a result, we used the $parent syntax to access the ViewModel.

When we click on Select button, KO passes the current data item to the selectBlog method. This is set to the ‘selectedBlog’ object. Since it’s an observable, KO refreshes anything that’s bound to it. We have bound the <div> using the ‘with’ syntax, to this object, this results in refreshing the div and its contents as well.

Just to make sure that Two way binding is actually working, change the text in Title and Post textboxes. You’ll notice the list changes immediately. And if you select a different item and come back to the modified item, you’ll see the changes are still there

two-way-data-binding

That covers basic data-binding in KO. Now let’s post this data to the server.

Posting Data back to the Server

To post data-back to the server, we can do it two ways - post the entire collection of blogs in one shot or post one blog at a time. Since we can have New objects mixed with updated objects in our View Model, I’ll take the shortcut of posting separately.

To initiate the post, we add a new Save button next to the ‘New Blog’ button. We assign a jQuery click handler as shown below.

$(document).ready(function ()
{
$(".right-section").hide();


   
$("#saveAll").click(function ()
{
  var saveData = ko.toJS(viewModel.blogs);
  $.each(saveData, function (index)
  {
   var current = saveData[index];
   var action = "PUT";
   var vUrl = "/api/Blogs?Id="+current.Id;
   if (current.isNew)
   {
    action = "POST";
    vUrl = "/api/Blogs";
   }
   $.ajax(
   {
    url: vUrl,
    contentType: "application/json;charset=utf-8",
    type: action,
    data: JSON.stringify(current)
   });
  });
});
});

The click handler first converts the observable view model into simple JavaScript object using the ko.toJS helper method. Next we loop through each blog object and check to see if the object has its IsNew property set to true (for new blog items it’s set to true in the newBlog behavior method above). Depending on whether it’s new or not, we decide on the action (PUT or POST). Finally we use jQuery’s ajax method to post the data to Web API.

Note: If you don’t have the contentType set to “application/json”, Web API will not be able to map your JSON data into Domain object on the server side.

Based on the type of action, the appropriate method is called on the server side and data gets updated. If you refresh the page now, you’ll see that the new/updated data in the list.

data-post-back-and-refresh

Conclusion

We took a look at the fundamentals of View Models and Databinding in Knockout JS. As we saw, it really takes client-side interactivity to a new level. Combined with ASP.NET Web API, it forms a nice Client-Server tango for creating rich and interactive web applications.

Download the entire source code over here (Github)

Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Suprotim Agarwal, ASP.NET Architecture MVP, MCSD, MCAD, MCDBA, MCSE, is the CEO of A2Z Knowledge Visuals Pvt. He primarily works as an Architect Consultant and provides consultancy on how to design and develop .NET centric database solutions.

Suprotim is the founder and primary contributor to DotNetCurry, DNC .NET Magazine, SQLServerCurry and DevCurry. He has also written an EBook 51 Recipes using jQuery with ASP.NET Controls. and authored a new one at The Absolutely Awesome jQuery CookBook.

Follow him on twitter @suprotimagarwal


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by W. Paap on Friday, April 5, 2013 2:51 AM
You should also have a look at the mapping plugin: http://knockoutjs.com/documentation/plugins-mapping.html for fetching your models in a generic way.
Comment posted by Suprotim Agarwal on Friday, April 5, 2013 4:57 AM
thanks for that link W. Paap Will go through it soon!
Comment posted by Brian Noronha on Tuesday, May 14, 2013 12:14 AM
Great Article...Just shows the potential that KnockoutJS holds.
Comment posted by Sakvith on Tuesday, June 25, 2013 12:56 PM
Thank you, this works perfectly..
Comment posted by Raiford G. Bonnell on Thursday, January 2, 2014 11:45 AM
Very nice job on this. Working through this sample  is an excellent way to get your head around Web API and KO ;-)
Comment posted by javier on Saturday, May 3, 2014 1:33 PM
And how do you do in the section "Posting Data back to the Server" if you want to send the entire colelction of blogs instead using foreach to send one by one?

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel