Share via



March 2012

Volume 27 Number 03

Client Insight - Knockout's Built-in Bindings for HTML and JavaScript

By John Papa | March 2012

John PapaKnockout brings a rich data-binding implementation to HTML5 and JavaScript development. Once you grasp the concept of observables, the easiest way to slide into development with Knockout is to understand the variety of built-in bindings it offers. Knockout’s built-in bindings are the simplest way to tap its data-binding features and add robust data binding to many aspects of your HTML5 apps. The previous column introduced Knockout, covered its various types of observables and explored the control of flow built-in bindings. This time I’ll delve further into Knockout’s built-in bindings. The code samples, which you can download from msdn.com/magazine/msdnmag0312, demonstrate how to use the various built-in bindings and explain the scenarios in which you might want to use them.

You can download the latest version of Knockout (currently 2.0.0) from bit.ly/scmtAi and reference it in your project, or you can use the NuGet Package Manager Visual Studio extension (available at bit.ly/dUeqlu) to download Knockout.

What Are the Built-in Bindings in Knockout?

At its most basic level, data binding requires a binding source (such as a JavaScript object) and a target to bind to (an HTML element, for example). The binding source is frequently called a view model. The target element may have several properties, so it’s important to know what target property to bind to, as well. For example, if you want to bind your view model firstName property to an input tag’s text, you’d want to bind to the Knockout value binding. In this case, Knockout identifies the target property through one of its built-in bindings: value. The Knockout built-in bindings allow you to bind to properties as well as methods of your view model. Knockout includes many built-in bindings that bind view model properties to target elements, as I’ll discuss in this article.

The syntax for using the built-in bindings is to include the Knockout binding name and the view model property pairs inside of the data-bind property of an HTML element. If you want to data bind to more than one property in the HTML element, simply separate the bindings by a comma using this syntax:

data-bind="built-in-binding:viewmodel-property1, another-built-in-binding:viewmodel-property2"

Following this pattern, you could bind the input element’s value to the view model salePrice property, like so:

<input type="text" data-bind="value:salePrice " />

Knockout’s built-in bindings allow you to handle most binding scenarios, but if you encounter a specialized binding scenario that isn’t covered, you can create custom bindings with Knockout, too. I’ll cover custom bindings in a future article.

Fundamental Bindings: text and html

Let’s dive in by exploring the built-in bindings Knockout provides. Figure 1 shows the view model that all of the examples in this article will use for their built-in bindings. The sample data is for a guitar, but it’s just to demonstrate the bindings.

Figure 1 View Model with Properties, Nested Children and Methods

my.showroomViewModel = {

  id: ko.observable("123"),

  salePrice: ko.observable(1995),

  profit: ko.observable(-7250),

  rating: ko.observable(4),

  isInStock: ko.observable(true),

  model: {

          code: ko.observable("314ce"),

          name: ko.observable("Taylor 314 ce")

  },

  colors: ko.observableArray([

          { key: "BR", name: "brown" },

          { key: "BU", name: "blue" },

          { key: "BK", name: "black"}]),

  selectedColor: ko.observable(""),

  selectedColorsForDropdown: ko.observableArray([]),

  selectedColorForRadio: ko.observableArray(),

  allowEditing: ko.observable(true),

  isReadonly: ko.observable(true),

    onSalesFloor: ko.observable(true),

    qty: ko.observable(7),

  photoUrl: ko.observable("/images/314ce.png"),

  url: ko.observable("https://johnpapa.net"),

  details: ko.observable("<strong><em>This guitar rocks!</em></strong>"),

  checkboxHasFocus: ko.observable(false),

  textboxHasFocus: ko.observable(false),

  buttonHasFocus: ko.observable(false),

  userInput: ko.observable(""),

  setFocusToCheckbox: function () {

          this.checkboxHasFocus(true);

  },

  displayValue: function () {

          if (this.userInput().length > 0) {

                  window.alert("You entered: " + this.userInput());

          }

  },

  detailsAreVisible: ko.observable(false),

  showDetails: function () {

          this.detailsAreVisible(true);

  },

  hideDetails: function () {

          this.detailsAreVisible(false);

  },

  useUniqueName: ko.observable(true)

};

ko.applyBindings(my.showroomViewModel);

Perhaps the most common binding is the text binding. When Knockout sees a text binding, it sets the innerText property for Internet Explorer, or the equivalent property in other browsers. When the text binding is used, any previous text will be overwritten. The text binding is often used to display values in a span or div. This example binds the view model’s model.code property to a span:

<span data-bind="text: model.code"></span>

The html binding isn’t used as often, but it’s very handy for rendering HTML content in your view model. In the following example, the contents of the html property are rendered, making the text bold italics:

<tr>

  <td><div class="caption">html</div></td>

  <td><div data-bind="html: details"></div></td>

  <td><span>details: </span><span data-bind="text: details"></span></td>

</tr>

You can see the results of these examples in Figure 2 (and all examples by running the 04-builtin-bindings.html page in the sample code). All examples show the built-in binding, the target and the source values from the view model.

The Knockout Text and HTML Bindings
Figure 2 The Knockout Text and HTML Bindings

Value Binding

Data binding is arguably most useful for apps that are very interactive, so it makes sense that most of the built-in bindings in Knockout help bind to input and form elements, such as textboxes, checkboxes and dropdown lists. Let’s explore these built-in bindings by first demonstrating the versatility of Knockout’s value binding.

The value binding works with many of the HTML input types to bind a view model property directly to the value of an HTML input element, such as a textbox checkbox or radio button. The following example shows the view model model.code property being bound to a textbox. The property is defined using Knockout’s observable function, which makes it notify the target when the source value changes:

<td><input type="text" data-bind="value: model.code"/></td>

<td><span>model.code: </span><span data-bind="text: model.code"></span></td>

If a user changes the value in the textbox, the new value is sent from the target (the textbox) to the source (the view model model.code property) when the user tabs away from the textbox. However, you could also use a special Knockout binding to tell Knockout to update the target to the source on every keystroke. In the next example, the textbox value is bound to the view model salePrice property and the valueUpdate binding is bound to afterkeydown. valueUpdate is a parameter for the value binding that helps you define when the value binding should be updated. Here the code is telling Knockout to update the source after every key down press (you can try this sample by running the sample code; the results are shown in Figure 3):

<td><input type="text" data-bind="value: salePrice, valueUpdate: 'afterkeydown'"/></td>

<td><span>salePrice: </span><span data-bind="text: salePrice"></span></td>

The Value Binding to Textboxes
Figure 3 The Value Binding to Textboxes

Binding Checkboxes and Radio Buttons

Checkboxes can be data bound to Knockout’s checked binding. The checked binding should be bound to a property or expression that evaluates to true or false. Because the view model properties are defined as observables, the checkbox is updated when the source property changes. Likewise, when a user checks or unchecks the checkbox, the value is updated in the view model property. The following example shows the checkbox being bound to the isInStock property (from the view model in Figure 1; the results are shown in Figure 4):

<td><input type="checkbox" data-bind="checked: isInStock"/></td>

<td><span>isInStock: </span><span data-bind="text: isInStock"></span></td>

The Checked Binding
Figure 4 The Checked Binding

You can also use the checked binding to select a radio button from a group of radio buttons. The following example shows a set of radio buttons whose values are all hardcoded to two-letter codes representing a color; when a user selects a color via the radio button, the checked property is set and the view model selectedColorForRadio property is updated to the two-letter value:

<td>

  <input type="radio" value="BR" data-bind=

    "checked:  selectedColorForRadio" /><span>brown</span>

  <input type="radio" value="BU" data-bind=

    "checked: selectedColorForRadio" /><span>blue</span>

  <input type="radio" value="BK" data-bind=

    "checked: selectedColorForRadio" /><span>black</span>

</td>

<td><span>selectedColorForRadio: </span><span data-bind=

  "text: selectedColorForRadio"></span></td>

While this works perfectly well, I find it more useful to data bind the list of colors to a series of radio buttons, which you can do by combining the three built-in bindings: value, checked and foreach. The view model in Figure 1 has a colors property, which is an array of objects containing each color’s name and a key value. The foreach binding in the next example loops through the colors array property, setting each radio button’s value binding to the color’s key property and a span’s text binding to the color’s name property:

<td>

  <div data-bind="foreach: colors">

    <input type="radio" data-bind=

      "value:key, checked: $parent.selectedColorForRadio" />

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

  </div>

</td>

<td><span>selectedColorForRadio: </span>

  <span data-bind="text: selectedColorForRadio"></span></td>

The radio button’s checked binding is set to the view model selectedColorForRadio property using the $parent function. However, the binding can’t simply be bound directly to that property because the foreach binding changed the context from the view model to the colors property. To properly bind to the view model’s property, the code needs to refer back the context’s parent (in this case the view model itself). The Knockout $parent function tells Knockout to refer one level up the context hierarchy, which data binds the checked binding to the view model selectedColorForRadio property. (There are many useful functions and tips like this that I’ll explore in future articles.) The results of this example are shown in Figure 5.

The Checked and Value Bindings Used in Radio Buttons
Figure 5 The Checked and Value Bindings Used in Radio Buttons

Binding Dropdown Lists

Dropdown lists have several important properties to load a list of items, display a value, use a different key value and store the user’s selection. Knockout provides a built-in binding for each of these.

The options binding identifies a list of values to display, usually from an array property on the view model. The example in this section sets the options binding to the view model colors property. Sometimes you want to display one value in the dropdown list but use another value when a user selects an item from the list. Knockout’s built-in optionsText and optionsValue bindings help. The optionsText binding is set to the string name of the property to display in the dropdown list, from the options binding. The optionsValue binding is set to the string name of the property to bind to for the selected value of the item in the dropdown list. In this example, the colors array contains objects with a name and key property, of which the name will be used for the optionsText and the key for the optionsValue. The value binding is set to the view model selectedColor property, where the user’s selection will be stored:

<td>

  <div class="caption">options, value, optionsText, optionsValue</div>

  <div>select (single selection dropdowns)</div>

</td>

<td><select data-bind="options: colors, value: selectedColor,

   optionsText: 'name', optionsValue: 'key'" ></select></td>

<td><span>selectedColor: </span><span data-bind="text: selectedColor"></span></td>

If you want to allow multiple selections from a dropdown list, you first add the multiple property for the HTML select element. Then you replace Knockout’s selectedOption (singular) binding with its selectedOptions (plural) binding:

<td>

  <div class="caption">options, selectedOptions, optionsText, optionsValue</div>

  <div>select (multiple selection dropdowns)</div>

</td>

<td><select data-bind="options: colors,selectedOptions: selectedColorsForDropdown,

  optionsText: 'name', optionsValue: 'key'" multiple="multiple" ></select></td>

<td><span>selectedColorsForDropDown: </span><span data-bind=

  "text: selectedColorsForDropdown"></span></td>

Because the HTML select element is allowing multiple selections, the view model selectedColorsForDropdown property (which is set to the selectedOptions built-in binding) will contain a comma-delimited list of values for the selections.

Figure 6 shows the results of selecting both the blue and black colors. Notice that the dropdown lists display the name of the color (blue and black), but use the key (BU and BK) as the selected values.


Figure 6 Binding to Dropdown Lists

Enabling and Disabling Input Elements

Knockout provides built-in bindings to enable and disable input elements. The enable binding will enable the input element if the property it’s bound to evaluates to true, and will disable the element if it evaluates to false. The disable binding does the exact opposite:

<td>

  <input type="checkbox" data-bind="checked: allowEditing"/>

  <input type="text" data-bind="enable: allowEditing, value:salePrice" />

</td>

<td><span>allowEditing: </span><span data-bind="text: allowEditing"></span></td>

This sample code demonstrates that the checkbox value is data bound to the view model allowEditing property, which is also bound to the textbox enable binding. So when the checkbox is checked, the textbox is enabled; when it’s unchecked, the textbox is disabled.

In contrast, the next sample demonstrates how the checkbox checked binding is bound to the view model isReadonly property and the textbox disable binding is set to the isReadonly property. So when the checkbox is checked, the textbox is disabled (the results of both samples can be seen in Figure 7):

<td>

  <input type="checkbox" data-bind="checked: isReadonly"/>

  <input type="text" data-bind="disable: isReadonly, value:salePrice" />

</td>

<td><span>is readonly: </span><span data-bind="text: isReadonly"></span></td>

Bindings for Enabling and Disabling Elements
Figure 7 Bindings for Enabling and Disabling Elements

Binding the Focus

Knockout has a built-in binding named hasfocus that determines and sets which element has the focus. The hasfocus binding is handy when you want the focus to be set to a specific element on a form. If multiple elements have the hasfocus binding with values that evaluate to true, the focus will be set to the element that had its hasfocus set most recently. You can set the hasfocus binding to the keyword true to move focus directly to an element. Or you can bind it to a view model property, as shown in the sample code in Figure 8.

Figure 8 Setting the Hasfocus Binding

<td>

  <input type="checkbox" data-bind="hasfocus: checkboxHasFocus"/>

  <input type="text" data-bind="hasfocus: textboxHasFocus"/>

  <button data-bind="click: setFocusToCheckbox, hasfocus:buttonHasFocus">

    set focus to checkbox</button>

  <br/>

  <span data-bind="visible: checkboxHasFocus">checkbox has focus</span>

  <span data-bind="visible: textboxHasFocus">textbox has focus</span>

  <span data-bind="visible: buttonHasFocus">button has focus</span>

</td>

<td>

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

    checkbox has focus</span>

  <br/>

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

    textbox has focus</span>

  <br/>

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

    button has focus</span>

</td>

This code sets the hasfocus binding appropriately for a checkbox, textbox and a button element to three different view model properties. When the focus is set to one of these HTML elements, the corresponding hasfocus binding sets the view model property to true for that element (and the others to false). You can try this example with the downloadable code, or see the results in Figure 9, where a user has placed the focus in the textbox.

Binding for Setting the Focus
Figure 9 Binding for Setting the Focus

Binding the Visibility

Knockout’s visible binding should be bound to a property that evaluates to true or false. This binding will set the element’s display style to visible if true (either true or a non-null value) or none if false (false, 0, undefined or null).

The next sample shows the checkbox checked binding and the textbox visible binding both set to the view model onSalesFloor property. When the checkbox is checked, the onSalesFloor property is set to true and the textbox becomes visible. When the checkbox is unchecked, the onSalesFloor property is set to false and the textbox is no longer visible (see Figure 10):

<td>

  <input type="checkbox" data-bind="checked: onSalesFloor"/>

  <input type="text" data-bind="visible: onSalesFloor, value:qty" />

</td>

<td>

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

</td>

Binding for Visibility
Figure 10 Binding for Visibility

Event Bindings

Knockout supports binding to any event through its event built-in binding, but it also has two special built-in bindings for click and submit. The click binding should be used on an element when you want to bind the click event to a method in a view model. It’s most often used with a button, input or an a element, but can be used with any HTML element.

The following code sets the button click binding to the displayValue method on the view model; in Figure 1, you can see that the displayValue method on the view model simply displays the view model userInput property (which is bound to the textbox) with an alert:

<td>

  <input type="text" data-bind="value: userInput"/>

  <button data-bind="click: displayValue">display value</button>

</td>

<td>

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

</td>

When you want to bind a view model method to an event other than click, you can use Knockout’s event binding. Because the click binding is the most-used binding for events, it’s simply a shortcut to the event binding.

Knockout’s event binding allows you to bind to any event. To use event binding, you pass an object literal containing name value pairs for the event name and the view model method, separated by commas. The following sample code sets Knockout’s built-in event binding so that the mouseover and mouseout events are bound to the showDetails and hideDetails methods on the view model. These methods set the view model observable property detailsAreVisible to true or false, accordingly:

<td>

  <div data-bind="text:model.code, event: {mouseover: showDetails,

    mouseout: hideDetails}"></div>

  <div data-bind="visible: detailsAreVisible" style="background-color: yellow">

    <div data-bind="text:model.name"></div>

    <div data-bind="text:salePrice"></div>

  </div>

</td>

<td>

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

</td>

The second div sets the visible binding to the view model details­AreVisible property, so when the user moves the mouse over the first div, the second div becomes visible. When the mouse is moved away from the first div, the second div is no longer visible. The results are shown in Figure 11. The submit binding (not shown in Figure11) accepts any input gesture that will submit an HTML form.

The Click and Event Bindings
Figure 11 The Click and Event Bindings

Style Bindings

You can bind styles with Knockout using the css and the style built-in bindings. The css binding can be set to one or more valid css class names. The following sample shows that the textbox has its value binding set to the view model profit property and its css binding set to an object literal. The object literal contains one or more css class names to apply and a corresponding expression that should evaluate to true or false:

<td>

  <input data-bind="value:profit, css: {negative: profit() < 0,

    positive: !(profit() < 0), }"/>

</td>

<td>

  <span>profit < 0: </span><span data-bind="text: profit() < 0 ?

    'negative' : 'positive'"></span>

</td>

For example, if the profit property evaluates to less than 0, the css class named negative will be applied. Similarly, the second expression is evaluated and if it’s true, the css class named positive will be applied.

While I recommend using css classes whenever possible, at times you might want to set a specific style as well. Knockout supports this with its style built-in binding. In the following example, the textbox color changes to red if the profit is less than 0, and to green if the profit is greater than 0 (the results for both the css and style bindings are shown in Figure 12):

<td>

  <input data-bind="value:profit, style: {color: profit() < 0 ? 'red' :

    'green'}"></input>

</td>

<td>

  <span>profit < 0: </span><span data-bind="text: profit() < 0 ? 'red' :

    'green'"></span>

</td>

Style Bindings
Figure 12 Style Bindings

Binding to Other HTML Attributes

While Knockout has many built-in bindings, you will surely encounter some situations for which none exist. For these, Knockout offers the attr built-in binding, which allows you to data bind any attribute to a view model property. This is very useful in many common scenarios, such as binding the href and title of the a element:

<td>

  <a data-bind="attr: {href: url, title: model.name}, text:model.code"></a>

</td>

<td><span>url: </span><span data-bind="text: url"></span></td>

Another common use for the attr binding is to make the img element bind its src attribute to the view model photoUrl property (you can see the results of both of these samples in Figure 13):

<td>

  <img data-bind="attr: {src: photoUrl, alt: model.code}" class="photoThumbnail"/>

</td>

<td><span>photoUrl: </span><span data-bind="text: photoUrl"></span></td>

Binding to Element Attributes
Figure 13 Binding to Element Attributes

Wrapping Up

This article explored many of the built-in bindings that Knockout offers. There are a few others, most notably the template binding, which I’ll cover in a future article. In any case, the concepts are the same. Determine the binding property you want to use on the target element and the view model member to which you want to bind it. Once you grasp Knockout’s observables and its variety of built-in bindings, you have the fundamental building blocks to create robust Web apps using the Model View ViewModel, or MVVM, pattern.


John Papa is a former evangelist for Microsoft on the Silverlight and Windows 8 teams, where he hosted the popular Silverlight TV show. He has presented globally at keynotes and sessions for conferences such as BUILD, MIX, Professional Developers Conference, Tech·Ed, Visual Studio Live! and DevConnections. Papa is also a columnist for Visual Studio Magazine (Papa’s Perspective) and author of training videos with Pluralsight. Follow him on Twitter at twitter.com/john_papa.

Thanks to the following technical expert for reviewing this article: Steve Sanderson