Getting Started with Knockout.js for .NET Developers

4 (2 reviews total)
By Andrey Akinshin
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies

About this book

Knockout MVC is a library for ASP.NET MVC that helps developers to move their entire business logic to the server.

With practical and accessible guidance, you will learn the skills necessary to successfully create Knockout.js-based applications of varying complexity.

Beginning with a vital overview of Knockout.js, including the MVVM design pattern, you will create a simple but powerful application capable of integrating with ASP.NET MVC as well as gain a thorough understanding of the Knockout MVC library. From this starting point, you will explore great advanced features that can be used in pure Knockout.js applications and server ASP.NET MVC logic, such as regions and complex bindings, as well as how to use the MVMM design pattern to create powerful sites separating the model, logic, and view layers.

Publication date:
May 2015
Publisher
Packt
Pages
188
ISBN
9781783984008

 

Chapter 1. Introduction to Knockout.js

Knockout.js is a popular JavaScript library that allows easy creation of powerful web applications based on the Model-View-ViewModel (MVVM) design pattern.

In this chapter, we will cover the following topics:

  • Knockout.js overview

  • Installing Knockout.js

  • Knockout.js fundamentals

 

Knockout.js overview


In this section, we will take a look at Knockout.js, including a brief introduction and the best features. If you already have some experience with the library, then you can skip this chapter and go to Chapter 2, Creating a Simple Knockout.js Application, to read about the advanced features.

What is Knockout.js?

Knockout.js is an open source standalone JavaScript library developed by Steve Sanderson in 2010. The main concept of the library is implementation of the Model-View-ViewModel design pattern for web applications on the client side. The library has powerful tools to make your JavaScript code and HTML/CSS markup easier and more readable with the help of so-called observables objects and declarative bindings.

Thus Knockout.js can help you create rich HTML pages with a clean underlying data model and dynamically self-updatable UI even for very big applications with complex logic and interfaces.

The best features

Knockout.js has a lot of features that distinguish it from other similar JavaScript frameworks. There are different solutions to create the common logic of your application and interaction between data and user interface. When you select the main library to build an application, you should understand its benefits.

The following are the best features of Knockout.js:

  • Nice dependency tracking based on MVVM: Once data is changed, HTML will be automatically updated. You shouldn't think about updating DOM when writing logic code. We will discuss the MVVM pattern in more detail later.

  • Two-way declarative bindings: This is a very simple way to link DOM elements to your data model, as shown in the following line of code:

    <button data-bind="enable: items().count < 7">Add</button><input data-bind="value: username" />
  • Simple and extensible: You can write your own type of declarative bindings for any purpose. Each new binding is defined by two simple functions for the init and update events. For example, you can define a binding for the duration of a slide animation, as follows:

    <div data-bind="slideDuration: 600">Content</div>
  • Absence of dependency: You don't need any third-party libraries. However, you may need the jQuery library for some advanced features support or performance issues, but most applications already use this library.

  • Pure JavaScript: Knockout.js doesn't use any JavaScript superstructure, such as TypeScript or CoffeeScript. The source code of the library is represented by the pure and readable JavaScript code; it works with any server- or client-side technology.

  • Compatibility with mainstream browsers: Knockout.js supports Mozilla Firefox 2+, Google Chrome 5+, Opera 10+, Safari, and even Internet Explorer 6+. It also works excellently on mobile (phone and tablet) devices.

  • Small size: The size of Knockout.js is around 46 KB after gzipping for version 3.1.0. The debug versions (without compression) have a size of around 214 KB but you don't need it in the production case.

  • Templating: The powerful template system will allow you to create reusable HTML chunks, which you can use for parts of a web page. It also has a nice syntax, as shown in the following code:

    <script type="text/html" id="person-template">
        <h3 data-bind="text: name"></h3>
        <p>Credits: <span data-bind="text: credits"></span></p>
    </script>

MVVM design pattern

The Model-View-ViewModel is a design pattern with a clear separation of the user interface from business logic. The main components of MVVM are as follows:

  • Model: This represents the state and operations of your business objects and is independent of UI. When using Knockout.js, you will usually make Ajax calls to some server-side code to read and write this stored model data.

  • View: This is a visible UI representing your business objects.

  • ViewModel: This is an intermediary between the View and Model, and is responsible for handling the UI logic.

You can see the scheme of MVVM in the following diagram:

The MVVM pattern looks like the classic Model-View-Controller (MVC) pattern. The Model is also your stored data, the View is also a graphical representation of your data for the user, but instead of a controller, MVVM uses a ViewModel for interaction between the Model and View. The MVVM has a number of advantages over the MVC, such as the following:

  • Low coupling: It's a property of the MVVM by design, because of which we use a clearer separation between the data, interface, and behavior. MVVM has a clearer separation between the data, interface, and behavior for most application architectures.

  • Testable: Low coupling makes the application more comfortable for unit-testing; now you can separately test each layer of your application. Testing UI logic by testing only ViewModel is an easier way than testing a complete HTML page.

  • Сode extensibility: Separation by layers makes it easier to extend each specific part of the code without affecting the others.

  • Two-way data-binding: This avoids having to write a lot of boilerplate code.

Let's consider MVVM in examples. In parentheses, you can see the representation format of each layer, but note that these are just examples; different applications use different formats:

  • Knockout.js: This is the target case for this book. Most often, a Knockout.js application will use the following schemes:

    • Model: This includes some data on the server side; you can read and write it via Ajax calls (JSON).

    • View: This is the web page (HTML/CSS).

    • ViewModel: This is the representation of data and operations (JavaScript).

  • WPF: Many .NET developers are familiar with MVVM on technologies such as WPF, Silverlight, and WinRT. Originally, the MVVM pattern was conceived to support WPF and Silverlight. For example, you can use the following scheme in your WPF application:

    • Model: This includes some data in the client database (binary)

    • View: This is the user interface of the WPF application (XAML)

    • ViewModel: This is the special data context classes (C#)

In this book, we will not explain MVVM in detail because the easiest way to understand MVVM is a careful study of the examples in this book. The examples will work only with View and ViewModel because communication with a real data model (commonly, some data on the server, which can use SQL, RSS, XML, binary, and so on) is another story. Within these examples, you can consider the ViewModel as the Model as well because it actually holds all your data. In a real application, you should select a way to transfer this data to the server.

 

Installing Knockout.js


There are a few ways to install Knockout.js, and each method is outlined here. Generally, you want to use the first or second method, but the third and fourth methods can be useful in some special cases.

Method 1 – official site

You can manually download Knockout.js from the official site http://knockoutjs.com/. You can see the screen of the main page in the following screenshot:

After downloading, you can add a reference to Knockout.js from your HTML page using a <script> tag. For example, if the library was downloaded to the root directory of your application, then you can use the following line of code:

<script type='text/javascript' src='knockout-3.1.0.js'></script>

You should use the actual version of the library instead of version 3.1.0 (released in March 2014) in the preceding example line of code. Hereafter, we will use version 3.1.0 (it is the current version at the time of writing this book), but because of backward compatibility all examples should work with future Knockout.js versions very well.

Also, you can download the debug build for learning purposes (from the download page at http://knockoutjs.com/downloads/index.html). It helps you to understand how Knockout.js works. Don't use it for real production applications.

Method 2 – NuGet

If you develop a website with .NET, you can install it via NuGet (https://www.nuget.org/packages/knockoutjs). Just run the following command in the Package Manager Console:

Install-Package knockoutjs

Method 3 – CDNs

Content distribution network (CDN) is a large system for delivery or distribution of some content to end users' servers. You can use third-party CDNs for reference Knockout.js. Examples of CDNs can be found at http://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js and http://ajax.aspnetcdn.com/ajax/knockout/knockout-3.0.0.js.

Note that not all CDNs support the latest actual version of the library. The best way is to use a local library version on your server, but the CDNs method can be very useful for quick single-page solutions.

Method 4 – GitHub

Full sources of the library are placed on GitHub at https://github.com/knockout/knockout. You can build the latest Knockout.js version from source by yourself by executing the following steps:

  1. Clone the repo from GitHub. Make sure that you have Git installed on your local machine:

    git clone https://github.com/knockout/knockout.git
    cd knockout
    
  2. Acquire build dependencies. Make sure that you have Node.js installed on your local machine:

    npm install -g grunt-cli
    npm install
    
  3. Run the build tool:

    Grunt
    

Done! Now you can find the built files in the build/output/ directory.

 

Knockout.js fundamentals


In this section, you will learn how to create a very simple "Hello World" application with step-by-step instructions. Each step will describe one of the main Knockout.js concepts.

Creating a View

Let's learn about Knockout.js with a very simple example. We start work with the following code of an HTML page (HelloWorld-Example1.html):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Hello world on Knockout.js</title>
  </head>
<body>
<span>Hello World!</span>

<script type='text/javascript' src='knockout-3.1.0.js'></script>
</body>
</html>

If we open this page in our favorite web browser, we will see the blank page with a single line, Hello World!. The body of this HTML page is the View layer of our MVVM pattern.

However, we did not use Knockout.js in this example. Let's change it.

Adding a ViewModel

Let's add some JavaScript code to our example. We will move information about the printed string from the View layer (HTML page) to the ViewModel layer (JavaScript object):

<script type='text/javascript'>
  var viewModel = {
    message: "Hello world!"
  };
  ko.applyBindings(viewModel);
</script>

In this example, the viewModel is a simple JavaScript object with a single message property. In the last line of the script, we activated Knockout.js by the applyBindings method of a global Knockout.js object called ko. The first parameter takes the ViewModel object that you want to use.

It's time to connect ViewModel with our HTML.

Adding a data binding

Let's change the inline Hello World! string to an empty span element with data binding (the full code of the page is placed in HelloWorld-Example2.html):

<span data-bind="text: message"></span>

The syntax of Knockout's declarative bindings provides a powerful way to link your data (the View) with your UI (the ViewModel). You can see an example of such syntax in the preceding HTML line; it consists of two parts (as a value of the data-bind property), the binding name and value, separated by a colon. In the example, we bind the text property of the span element to the user-defined message property of ViewModel.

Because of the message property, the content of the span element is Hello world!. The rendered HTML page is still represented by a single text line.

Adding an observable

Now our example has one thing lacking: changes of the ViewModel don't link to changes of the View. We can improve the situation with observables. Let's update the viewModel definition (see HelloWorld-Example3.html):

var viewModel = {
  message: ko.observable()
};
viewModel.message("Hello world!");
ko.applyBindings(viewModel);

In this example, message is an observable property. It means that after any changes to the message property, UI elements with corresponding bindings will be automatically updated.

You should understand that the ko.observable properties are actually functions. Therefore, you can use these functions to read and write. If you want to write some value in a property, you should call an observable function with a new value as the first parameter (such as in the preceding listing). If you want to read a value from a property, you should call the observable function without any parameters:

viewModel.message("Hello, world!");   // Write operation
currentMessage = viewModel.message(); // Read operation

The observables are the most important part of the Knockout.js MVVM structures. All of your ViewModel properties that are involved in the UI update process should be defined as an observable (such as in the preceding code via ko.observable). A non-observable property will work only for one-time read-only data binding. It may be useful for some special cases, but generally, you should describe all of your ViewModel properties as observables.

Also, you can set the initial observable value directly in the definition (for example, message: ko.observable("Hello world!")).

Subscribing to observables

Most applications don't need an explicit way to subscribe to observables (such operations are performed implicitly using the declarative style), but in some special scenarios, it may be useful. Now we consider the explicit way for a better understanding of the observables concept.

Explicitly subscribing means declaring a callback with the subscribe function, as shown in the following example (see HelloWorld-Example4.html):

viewModel.message.subscribe(function(newValue) {
  alert("New message is " + newValue);
})

After this subscription, any changes to the message property would entail an alert message about the changes.

In a real application, it may be useful to create an additional logic for the observable property change event that you can't make by the usual declarative bindings.

Updating View in a forced way

A data binding can have additional properties. Let's consider an example. By default, the View layer gets a notification about data changes only if the data was actually changed. However, we can modify this behavior and make ViewModel always send notifications. For this purpose, you will use the so-called notify extender to ensure that our subscribers are always notified on a write request, even if the new property value is the same:

viewModel.message.extend({ notify: 'always' });

In the preceding line of code (see HelloWorld-Example5.html), we call the extend function to update the notify property of message by the always value.

In a real application, it may be useful if you want to notify a user about any change operation of data, regardless of a new value.

Delaying and suppressing change notifications

Let's consider another extender example. Normally, an observable notifies its subscribers immediately, as soon as it's changed. However, if an observable is changed repeatedly or triggers expensive updates, you may get better performance by limiting or delaying the observable's change notifications, as follows:

viewModel.message.extend({ rateLimit: 100 });

In the preceding line of code (see HelloWorld-Example6.html), we call the extend function to update the rateLimit property of message by 100. It means that ViewModel will notify the View about changes no more than once in every 100 milliseconds.

Adding dynamic behavior

It's time for a more interesting example. We will add some dynamic behavior. Let's insert a button to add an exclamation mark to our message. The new representation of the View layer will be as follows:

<span data-bind="text: message"></span><br />
<button data-bind="click: addExclamationMark">Add exclamation mark</button>

The representation of the ViewModel layer will be as follows:

var viewModel = {
  message: ko.observable(),
  addExclamationMark : function() {
    this.message(this.message() + "!")
  }
};
viewModel.message("Hello world!");
ko.applyBindings(viewModel);

In the View, we can see the button with the new declarative binding: click. This binding expression sets the click button event handler to addExclamationMark. We can find the declaration of this function in the ViewModel:

  addExclamationMark : function() {
    this.message(this.message() + "!")
  }

In the body of the function, we used the message property twice: once to read and once to write. More specifically, we took the current value of message, added an exclamation mark to the obtained string value, and set the composite string as the new message value.

Try to run the example (HelloWorld-Example7.html) and click on the button. You will see how the message is modified, as shown in the following screenshot:

A binding diversity

There are different ways to use Knockout.js declarative bindings. We will consider it in the following chapters, but for now, you can briefly look at the following binding example to understand the diversity of opportunities that you have with Knockout.js. You can find the full list of examples with comments in the BindingDiversity.html file.

Single and multiple bindings

An element can use a single binding (described by the name and value) or multiple bindings (related and unrelated). In the last case, each binding should be separated from the previous one by a comma:

<!-- Single -->
<span data-bind="text: message"></span>

<!-- Multiple related -->
<input data-bind="value: name, valueUpdate: 'afterkeydown'" />

<!-- Multiple unrelated -->
<input data-bind="value: name, enable: isNameEnable" />

Value representation

The value of a binding can be represented by a single value, variable, or literal. In addition, you can use some JavaScript expressions, including function calls, as shown in the following code:

<!-- Variable -->
<div data-bind="visible: shouldShowMessage">...</div>

<!-- Simple expression + value -->
<span data-bind="text: price() > 50 ? 'expensive' : 'cheap'"></span>

<!-- Functional call -->
<button data-bind="enable: parseAreaCode(cellphoneNumber()) !== '555'">...</button>

<!-- Function expression -->
<div data-bind="click: function (data) { myFunction('param1', data) }">...</div>

<!-- Object literal -->
<div data-bind="with: {emotion: 'happy', 'facial-expression': 'smile'}">...</div>

Note that such examples demonstrate a kind of bad practice because the good way encapsulates all the logic in the ViewModel layer.

White spaces

White spaces (spaces, tabs, and newlines) do not affect bindings. The following examples are all equivalent:

<!-- Without spaces -->
<select data-bind="options:availableCountries,optionsText:'countryName',value:selectedCountry,optionsCaption:'Choose...'"></select>

<!-- With spaces -->
<select data-bind="options : availableCountries, optionsText : 'countryName', value : selectedCountry, optionsCaption : 'Choose...'"></select>

<!-- With newlines -->
<select data-bind="
    options: availableCountries,
    optionsText: 'countryName',
    value: selectedCountry,
    optionsCaption: 'Choose...'"></select>

Skipping the value

If you use Knockout.js 3.0+, you can use the binding without a value, as shown in the following code. In this case, binding will have an undefined value. It can be useful with binding preprocessing (you will learn about this feature in future chapters):

<!-- Without a value -->
<span data-bind="text">Text that will be cleared when bindings are applied.</span>

Useful links

You can find more useful information about Knockout.js at the following links:

Information about Knockout.js developers can be found at the following links:

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

 

Summary


In this chapter, we got acquainted with Knockout.js, what it is what its benefits are, how to download and install it, and how to write a simple "Hello World" application. In addition, we covered the MVVM design pattern and how it helps us to build a nice application with the help of Knockout.js. The Hello World example demonstrates basic Knockout.js features, such as observables, data bindings, subscribing logic, and its extenders.

About the Author

  • Andrey Akinshin

    Andrey Akinshin has a PhD in computer science, and he received a Microsoft MVP award in 2015. He works as a lead .NET Developer at Perpetuum Software and as a postdoctoral research fellow at the Weizmann Institute of Science. He is also the author and main contributor of the Knockout MVC library and has a wealth of experience in Knockout.js. He has experience in various IT areas, from competitive programming (silver medal at ACM ICPC 2009) to teaching (senior lecturer and the school coach of competitive programming and mathematics teams).

    You can find more information about Andrey on his home page, http://aakinshin.net.

    Browse publications by this author

Latest Reviews

(2 reviews total)
Good
Good