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.
- <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
- public class Candidate
- {
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public string Email { get; set; }
- public int Experience { get; set; }
- public string[] Technologies { get; set; }
- }
View Model object in JavaScript
Let’s create a JavaScript View Model object with name candiateModel for providing data to the user interface page
- var candidateModel = {
- FirstName: ko.observable(''),
- LastName: ko.observable(''),
- Email: ko.observable(''),
- Experience: ko.observable(0),
- Technologies: ko.observableArray([]),
- TechnologyToAdd: ko.observable('')
- };
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.
- candidateModel.Name = ko.dependentObservable(function () {
- return candidateModel.FirstName() +
- " " + candidateModel.LastName();
- });
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.
- candidateModel.addTechnology = function () {
- if (candidateModel.TechnologyToAdd() !== '') {
- candidateModel.Technologies.push(candidateModel.TechnologyToAdd());
- candidateModel.TechnologyToAdd('');
- }
- };
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.
- @{
- ViewBag.Title = "Add Candidate";
- }
- <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
- <script src="@Url.Content("~/Scripts/knockout-1.2.1.js")" type="text/javascript"></script>
- <form data-bind="submit: addCandidate">
- <fieldset>
- <legend>Candidate info</legend>
- <p>First Name: <input type="text" data-bind="value: FirstName" /> </p>
- <p>Last Name: <input type="text" data-bind="value: LastName" /> </p>
- <p>Email:<input type="text" data-bind="value: Email" /> </p>
- <p>Experience: <input type="text" data-bind="value: Experience" /> months </p>
- </fieldset>
- <fieldset>
- <legend>Technologies</legend>
- New Technology:
- <input type="text" data-bind='value: TechnologyToAdd, valueUpdate: "afterkeydown"' />
- <button type="submit" data-bind="enable: TechnologyToAdd().length > 0, click: addTechnology">Add</button>
- </fieldset>
- <fieldset>
- <legend>Candidate Profile</legend>
- <b><span data-bind="text: Name"></span></b>
- has <b><span data-bind="text: Experience"></span></b> month experience <br />
- Email : <b><span data-bind="text: Email"></span></b>
- <p>Technology Expertises</p>
- <select multiple="multiple" width="50" data-bind="options: Technologies"></select>
- </fieldset>
- <input type="submit" value="Create" />
- </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.
- <input type="text" data-bind="value: FirstName" />
The above input text is bind with view model object’s FirstName property.
- <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.
- <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.
- <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.
- ko.applyBindings(candidateModel);
Save Candidate
Let’s add a function to the view model for performing Ajax save using jQuery
- candidateModel.addCandidate = function () {
- $.ajax({
- url: "/Home/Create/",
- type: 'post',
- data: ko.toJSON(this),
- contentType: 'application/json',
- success: function (result) {
- alert(result);
- }
- });
- };
The form is bind with addCandidate function for submit
- <form data-bind="submit: addCandidate">
Let’s add an action method Create for handling Ajax save functionality
- [HttpPost]
- public JsonResult Create(Candidate candidate)
- {
- //do the persistence logic here
- var message = "Candidate: " + candidate.FirstName + " Saved";
- return Json(message);
- }
Final View Model object
The final JavaScript block is given below
- <script type="text/javascript">
- $(function () {
- //activates KO
- ko.applyBindings(candidateModel);
- });
- var candidateModel = {
- FirstName: ko.observable(''),
- LastName: ko.observable(''),
- Email: ko.observable(''),
- Experience: ko.observable(0),
- Technologies: ko.observableArray([]),
- TechnologyToAdd: ko.observable('')
- };
- candidateModel.Name = ko.dependentObservable(function () {
- return candidateModel.FirstName() +
- " " + candidateModel.LastName();
- });
- candidateModel.addTechnology = function () {
- if (candidateModel.TechnologyToAdd() !== '') {
- candidateModel.Technologies.push(candidateModel.TechnologyToAdd());
- candidateModel.TechnologyToAdd('');
- }
- };
- candidateModel.addCandidate = function () {
- $.ajax({
- url: "/Home/Create/",
- type: 'post',
- data: ko.toJSON(this),
- contentType: 'application/json',
- success: function (result) {
- alert(result);
- }
- });
- };
- </script>
The UI Page on the browser
The below screen shot shows the user interface of our demo app
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.