Knockout.js is a popular JavaScript framework for building dynamic user interfaces using the Model-View-ViewModel (MVVM) pattern. Knockout allows for easy one or two-way synchronization between your data and the markup. However, Knockout does not include any widgets or components for creating the user interface, which is a major strength of Kendo UI. The open source library Knockout-Kendo provides the integration needed to make these tools work together in a natural way.

Why use Knockout with Kendo UI?

Kendo UI does provide its own MVVM functionality that is tightly integrated with the Kendo UI widgets. If you are starting a project from scratch and plan to make heavy use of Kendo UI, then you might want to consider this option. However, you may already have experience with Knockout, want to add rich widgets to an existing Knockout-based user interface, or you might just prefer Knockout's syntax and functionality. In that case, Knockout and Kendo UI can be a powerful combination.

When using Knockout, all interactions between the DOM and your data are intended to happen in bindings. Knockout provides an extensibility point that allows you to extend the default bindings with your own custom bindings. Knockout-Kendo works by creating 23 custom bindings that represent all of the Web and DataViz widgets. Each custom binding conveniently handles the plumbing for these tasks:

  1. Instantiating the widget with any provided configuration options
  2. Subscribing to applicable events to update the view model data when users interact with the widget
  3. Calling methods on the widget in reaction to changes in observable view model data
  4. Destroying the widget if the element is removed from the page by Knockout

Using Knockout-Kendo

Getting started with Knockout-Kendo is easy. The library is hosted here on github and includes a documentation site that describes how to use each binding.

Installation

The Knockout-Kendo library will register bindings for any widgets that are available when it is loaded. This means that you will want to reference both Knockout and the Kendo UI scripts (along with jQuery) prior to Knockout-Kendo.

<script src="js/jquery.min.js"></script>
<script src="js/kendo.web.min.js"></script>
<script src="js/knockout-2.2.0.js"></script>
<script src="js/knockout-kendo.min.js"></script>

 

Knockout-Kendo is also AMD-aware, so it can be used with a dependency management library like require.js. In that scenario, the module depends on "knockout", "jquery", and "kendoui" modules. Depending on your setup, the "jquery" and "kendoui" modules may need to be added as part of the shim configuration.

Binding Basics

Each widget is represented with a custom binding that uses the same name as the widget. For example, the slider widget is available as a custom binding called kendoSlider. Each binding accepts an object containing any of the options that the widget supports:

<input data-bind="kendoSlider: { value: weight, enabled: enabled, min: 0, max: 100 }" />

 

The binding also supports a default option for the most common use case, which helps to keep the markup clean. For example, the slider widget can be bound directly against its value option like:

<input data-bind="kendoSlider: rank" />

 

Live options

While the bindings will accept any option that the particular widget supports, some of the options are designated as "live". When bound against an observable, these options will update the widget and/or be updated by the user interacting with the widget. The "live" options are based on the available APIs and events that the widget supports. The Knockout-Kendo documentation contains a section for each binding describing the "live" options for that widget.

For example, the slider has an enabled live option that you can bind against an observable boolean. As the value is toggled, the binding takes care of calling the widget's enable method to properly update the widget's state. There is generally no need to have a reference to the widget or call methods directly on the widget from your view model. This allows you to focus on the business logic and getting your data into an appropriate state to be bound against.

Here is a sample demonstrating the use of the kendoSlider binding:

Global options

Passing complex objects to a binding in markup can get verbose. One option to help keep your markup clean is to bind it against an object in your view model that represents the binding's options. However, many times you will want to reuse the same configuration each time that you use a binding. To support this scenario and to keep the markup simple, each binding supports global configuration options that can be defined in JavaScript. For example, you may want to set a default minimum and maximum for the slider widget:

ko.bindinghandlers.kendoSlider.options = {
    min: 0,
    max: 100
};

 

Now in cases where you do not need further customization of the options, you can simply bind against the value of the slider. The bindings will take the global options as defaults and then apply any configuration passed in through the binding string as overrides.

Advanced usage

To support such a large number of bindings, the Knockout-Kendo library uses a factory approach where bindings are built by passing in a configuration object that describes the widget's relevant events, methods, and options. Since the structure of each widget is similar, this approach makes it easy to generate additional bindings for new widgets and keeps the core logic centralized.

Generating your own bindings

You can also use the binding factory to generate bindings for your own custom Kendo UI widgets. For example, suppose that you create a custom "click-to-edit" widget, where you you display text as a link and when a user click's on it, then it becomes an input field for editing. Let's say that this widget exposes value and allowEditing methods to programmatically control the behavior of the widget. Additionally, the widget might trigger edit and view events when it changes state and a change event when the value changes.

To create a custom Knockout binding against the widget, we can call ko.kendo.bindingFactory.createBinding like:

ko.kendo.bindingFactory.createBinding({
    name: "kendoClickToEdit",
    defaultOption: "value",
    //events to bind against. update the view model based on interactions with the widget
    events: {
      change: "value",
      edit: {
        writeTo: "editable",
        value: true
      },
      view: {
        writeTo: "editable",
        value: false
      }
    },
    //observables to watch. react to changes by calling methods on the widget
    watch: {
      editable: "allowEditing",
      value: "value"
    }
});

 

The options passed to the binding factory have some flexibility in how they can make updates. In the above sample, when the change event is triggered, the binding will call the value method to retrieve the current value and update the observable passed as the value option. However, for the edit and view events, we indicate that we want to write to the observable passed in as editable and write a fixed value (true or false). A good way to understand the available options is to review how the bindings for each widget are prepared in the unminified source code.

Here is a sample demonstrating a custom Kendo UI widget and a generated Knockout binding for it:

Summary

Knockout.js and Kendo UI can be a terrific combination for developing slick and dynamic user interfaces. The Knockout-Kendo library is open source (MIT license) and provides everything that you need to use Kendo UI widgets through Knockout bindings. I am always happy to hear feedback, help with issues, or accept contributions related to the Knockout-Kendo bindings. Visit the project here or browse the documentation to get started today.


About the Author

Ryan Niemeyer

Ryan Niemeyer has been working with web technologies for the better part of 13+ years and lives just outside Madison, Wisconsin with his wife and two daughters. In his spare time, he loves to participate in open source development. He is a member of the Knockout.js core team, has written a number of Knockout plugins, and blogs about his experiences athttp://knockmeout.net.

Related Posts

Comments