Building JavaScript MVVM apps in ASP.NET MVC using KnockoutJS

JavaScript is getting more attention in modern web application development and increasing the popularity of JavaScript on every day. HTML 5 is making a revolution in web apps world and it is becoming a common platform for variety of scenarios. JavaScript is the language for HTML 5. The next question is how we can write highly maintainable JavaScript code and how to write testable JavaScript code. The answer would be to use a high level JavaScript framework such as KnockoutJS, BackboneJS and SpineJS. In this post, I will demonstrate how to use KnockoutJS in your ASP.NET MVC apps. KnockoutJS is an open source JavaScript library developed by Steven Sanderson. I am a big admirer of Steven Sanderson so I decided to first evaluate  KnockoutJS  and really excited about the framework so far. You can download the source code of the demo app from here

Introduction to KnockoutJS

KnockoutJS is a JavaScript MVVM framework that lets you create very rich, highly responsive web apps using JavaScript and HTML. Using KnockoutJS, you can create desktop-like user interfaces for your web apps with JavaScript. KnockoutJS framework is based on the MVVM design pattern. MVVM is stands for  Model – View – View Model and it is a design pattern for UI, originally introduced with Silverlight and WPF. In JavaScript MVVM, Model would be your application’s stored data that would be implemented using a server-side technology. The View would be user interface with HTML. The View Model would be a JavaScript object which contains data and operations for your View. One of the nice features of KnockoutJS is the automatic UI refresh when your JavaScript model object changes. KnockoutJS is providing a functionality named observable that let you sync your JavaScript View Model object with user interfaces. KnockoutJS is provides an elegant binding mechanism that would bind user interface with JavaScript View Model object.

Demo app with KnockoutJS

You can add KnockoutJS using NuGet. The following command in NuGet console will install  KnockoutJS  on your web app.

PM > install-package knockoutjs

The following script reference will add a reference to Knockout.js on our ASP.NET MVC demo app.

  1. <script src="@Url.Content("~/Scripts/knockout-1.2.1.js")" type="text/javascript"></script>

Let’s create an Model object in our ASP.NET MVC app

  1. public class Candidate
  2. {
  3.     public string FirstName { get; set; }
  4.     public string LastName { get; set; }        
  5.     public string Email { get; set; }
  6.     public int Experience { get; set; }
  7.     public string[] Technologies { get; set; }
  8. }

View Model object in JavaScript

Let’s create a JavaScript View Model object with name candiateModel for providing data to the user interface page

  1. var candidateModel = {
  2.     FirstName: ko.observable(''),
  3.     LastName: ko.observable(''),
  4.     Email: ko.observable(''),
  5.     Experience: ko.observable(0),
  6.     Technologies: ko.observableArray([]),
  7.     TechnologyToAdd: ko.observable('')
  8. };

The View Model object in JavaScript contains properties which values are specified as ko.observable(). Knockout will automatically updates the UI when the view model changes. When our properties specified as  observable, Knockout will notify the changes to its subscribers and will automatically detect dependencies. The property Technologies is a array so that we specified it as observableArray. The observableArray is same as other observable, but it can contains array of values. In our above view model object, we initializes with empty values for properties. In our demo app, we need to show the full name of the Candidate when there is any change in FirstName or LastName. Let’s add a Name property to our view model object for automatically updates the UI when there is any change in name fields.

  1. candidateModel.Name = ko.dependentObservable(function () {
  2.     return candidateModel.FirstName() +
  3.     " " + candidateModel.LastName();
  4. });

The Name property specified as dependentObservable because the Name property is dependent with other observable FirstName and LastName. Observables and dependent observables are key features of Knockout and the framework is doing automatic UI refresh using these features. Our view model candidateModel now contains the all properties for our UI. We need to add an operation for adding values to the Technologies array. The property TechnologyToAdd is using to represent the value for adding new technology to our array property Technologies. Let’s add an function to the view model for handling add technology operation.

  1. candidateModel.addTechnology = function () {
  2.     if (candidateModel.TechnologyToAdd() !== '') {
  3.         candidateModel.Technologies.push(candidateModel.TechnologyToAdd());
  4.         candidateModel.TechnologyToAdd('');
  5.     }
  6. };

The above addTechnology function will add the value of TechnologyToAdd property to our array property Technologies.

HTML View

Now we have created a JavaScript view model object for our UI. Let’s add view elements to our View page.

  1. @{
  2.     ViewBag.Title = "Add Candidate";
  3. }
  4. <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
  5. <script src="@Url.Content("~/Scripts/knockout-1.2.1.js")" type="text/javascript"></script>
  6. <form data-bind="submit: addCandidate">
  7.     <fieldset>
  8.         <legend>Candidate info</legend>
  9.         <p>First Name: <input type="text" data-bind="value: FirstName" /> </p>
  10.         <p>Last Name: <input type="text" data-bind="value: LastName" /> </p>
  11.         <p>Email:<input type="text" data-bind="value: Email" /> </p>
  12.         <p>Experience: <input type="text" data-bind="value: Experience" />&nbsp;months </p>         
  13.     </fieldset>
  14.     <fieldset>
  15.         <legend>Technologies</legend>
  16.         New Technology:
  17.         <input type="text" data-bind='value: TechnologyToAdd, valueUpdate: "afterkeydown"' />
  18.         <button type="submit" data-bind="enable: TechnologyToAdd().length > 0, click: addTechnology">Add</button>        
  19.     </fieldset>
  20.      <fieldset>
  21.    <legend>Candidate Profile</legend>
  22.     <b><span data-bind="text: Name"></span></b>
  23.     has <b><span data-bind="text: Experience"></span></b> month experience <br />  
  24.     Email : <b><span data-bind="text: Email"></span></b>
  25.     <p>Technology Expertises</p>
  26.         <select multiple="multiple" width="50" data-bind="options: Technologies"></select>    
  27.      </fieldset>     
  28.     <input type="submit" value="Create" />  
  29. </form>

Declarative binding is the powerful features of KnockoutJS. The view elements are bind with our view model object. For data binding,  Knockout is using data-bind attribute to HTML elements.

  1. <input type="text" data-bind="value: FirstName" />

The above input text is bind with view model object’s FirstName property.

  1. <span data-bind="text: Name"></span>

The above HTML element bind with view model object’s Name property. The Name property will automatically updates when there is any change in FirstName or LastName fields.

The button for adding new technology expertise is bind with addTechnology function of view model object.

  1. <button type="submit" data-bind="enable: TechnologyToAdd().length > 0, click: addTechnology">Add</button>

The select element is bind with array property Technologies so that it automatically add items when there is any new item added to the Technologies property.

  1. <select multiple="multiple" width="50" data-bind="options: Technologies"></select>

Activates KnockoutJS

The below code in the JavaScript will activates KnockoutJS with our view model object. So it will bind the values of view model with HTML elements.

  1. ko.applyBindings(candidateModel);

Save Candidate

Let’s add a function to the view model for performing Ajax save using jQuery

  1. candidateModel.addCandidate = function () {
  2.     $.ajax({
  3.         url: "/Home/Create/",
  4.         type: 'post',
  5.         data: ko.toJSON(this),
  6.         contentType: 'application/json',
  7.         success: function (result) {
  8.             alert(result);
  9.         }
  10.     });
  11. };

The form is bind with addCandidate function for submit

  1. <form data-bind="submit: addCandidate">

Let’s add an action method Create for handling Ajax save functionality

  1. [HttpPost]
  2. public JsonResult Create(Candidate candidate)
  3. {
  4.     //do the persistence logic here
  5.     var message = "Candidate: " + candidate.FirstName + " Saved";
  6.     return Json(message);
  7. }

Final View Model object

The final JavaScript block is given below

  1. <script type="text/javascript">
  2. $(function () {
  3. //activates KO
  4. ko.applyBindings(candidateModel);
  5. });
  6. var candidateModel = {
  7.     FirstName: ko.observable(''),
  8.     LastName: ko.observable(''),
  9.     Email: ko.observable(''),
  10.     Experience: ko.observable(0),
  11.     Technologies: ko.observableArray([]),
  12.     TechnologyToAdd: ko.observable('')
  13. };    
  14. candidateModel.Name = ko.dependentObservable(function () {
  15.     return candidateModel.FirstName() +
  16.     " " + candidateModel.LastName();
  17. });
  18. candidateModel.addTechnology = function () {
  19.     if (candidateModel.TechnologyToAdd() !== '') {
  20.         candidateModel.Technologies.push(candidateModel.TechnologyToAdd());
  21.         candidateModel.TechnologyToAdd('');
  22.     }
  23. };
  24. candidateModel.addCandidate = function () {
  25.     $.ajax({
  26.         url: "/Home/Create/",
  27.         type: 'post',
  28.         data: ko.toJSON(this),
  29.         contentType: 'application/json',
  30.         success: function (result) {
  31.             alert(result);
  32.         }
  33.     });
  34. };
  35. </script>

The UI Page on the browser

The below screen shot shows the user interface of our demo app

candidate_fullui

The candidate profile section would be automatically refresh when there is any change in the input fields. 

Source Code

You can download the source code from here

Summary

KnockoutJS is an excellent JavaScript library that lets you to build desktop like user interface with JavaScript and HTML. This post is just an introductory post on KnockoutJS  and the real power of KnockoutJS is really exciting. You can get more details of KnockoutJS from the product web site http://knockoutjs.com. The knockout web site provides very nice documentation and lot of examples that would be very helpful to build real world web apps with KnockoutJS  and your favorite server-side and technology. You can build very exciting web apps with ASP.NET MVC and KnockoutJS.

16 Comments

  • Fantastic post. I use backbone at the moment, but I here good things about Knockout. Still not sure which is better. Thanks for the post.

  • where is ASP.NET MVC in this??

  • @tkmagesh77 The demo app written in ASP.NET MVC

  • @shiju - I think @tkmagesh77 is being sarcastic... Your model is in C# and everything else is in JavaScript (OK - there is a small Post method from controller). What I would expect from an MVC article (as opposed to an article on Knockout web page which has excellent docs, btw) - how MVC application DRYly (or better yet, unobtrusively) integrates with Knockout view model on the client.

    This article is a good start, though!

  • It would be interesting if the "var candidateModel = {..." declaration is automatically generated with the observable's using reflection. ovbiusly this can be done during build or by an action method in some controller.

  • Knockout JS would rock if there was some kind of plugin to auto generate the JS from your .Net ViewModels...

  • Great article. Thanks much for taking the time to write it. I consuming JSON from a RESTful service, and was looking for a way to work with the View layer using JSON.

  • Need a more fully worked application to see whats going on something that explodes the comments of September 19th and 21st 2011

  • Really nice, simple and ez example to start with. And of course me too a big admirer of Steven Sanderson. Hats off for his development of KnockoutJS.

  • Thanks and Nice article. Easier for mvc developers to get into knockout.js

  • I tend not to drop a ton of comments, but i did some searching and wound up here
    Building JavaScript MVVM apps in ASP.NET MVC using KnockoutJS - Shiju Varghese's Blog
    .
    And I actually do have a couple of questions for you if you tend not to mind.
    Is it just me or does it look like a few of the comments come
    across like coming from brain dead people?
    :-P And, if you are writing at additional social sites,
    I'd like to keep up with everything fresh you have to post. Could you list of all of all your public sites like your twitter feed, Facebook page or linkedin profile?

  • Hi Shiju,

    I am Vivek (xMVP). I have read this article and i really enjoyed it.

    You are truly helping community and i would like to personally thank you for your great work.

    Since i am trying to learn MVVM, is it possible to have more examples on MVVM and asp.net MVC.

    Thank you.

  • Really good article! Good point of view to MVC/Razor + javascript. This is exactly what I was looking for.

    Many thanks and good work.

  • This code is not working for MVC 2.0.... Whether the code written is not compatible with MVC 2.0 ?
    Issue is data posted to action method is not mapped with the model. the model object is always null

  • Wonderful work! That is the kind of info that are meant to be shared across the
    web. Shame on Google for now not positioning this put up upper!
    Come on over and visit my web site . Thanks =)

  • This post was really helpful to me. You have differentiate each and every term very nicely. One important thing i have noticed which can be improved is how to define ViewModel. The core concept of separating javascript from view was not very cleared to me.

    If possible could you please explain that concept, since it is very important about how you define architecture of asp.net mvc application, while dealing with View Model.

    Thanks you

Comments have been disabled for this content.