Knock Me Out

Thoughts, ideas, and discussion about Knockout.js

KO 1.3 Preview Part 2: Custom Binding Providers

| Comments

Update: Knockout 1.3 was eventually renamed to version 2.0

I am really excited about the changes coming in Knockout 1.3. In the previous post, I discussed the native template engine. It will likely change the way that we all write Knockout apps. The next feature that I find very intriguing is the ability to swap in a custom binding provider.

What is a binding provider?

To understand what a binding provider is all about, let’s talk about the default binding provider that comes with Knockout 1.3. The default binding provider looks for any elements that have a data-bind attribute. When the binding provider finds an element with this attribute, then it will parse the attribute value and turn it into a binding object using the current data context. This works in the same way as bindings have always worked in Knockout. You declaratively add your bindings to the elements that you want and Knockout binds them to the current data at that level.

What does a custom binding provider look like?

A binding provider only has to answer two simple questions:

  1. Given a DOM node, does that node have any bindings?
  2. Given a DOM node (that passed #1) and the current data context, what does the binding object look like?

A binding provider is an object that implements two functions:

1
2
3
4
5
6
7
8
9
var yourBindingProvider = {
    nodeHasBindings: function(node) {
        //return true/false
    },

    getBindings: function(node, bindingContext) {
        //return a binding object
    }
};

The nodeHasBindings function takes in a DOM node. Remember that this is a node, so it is not necessarily an element. In fact, the default binding provider looks at comment nodes to see if they are containerless bindings.

The getBindings function expects you to return an object that represents the bindings as applied to the current data context. For example, if you want to apply a text binding with the value of the current data’s name observable, then you would return an object like: { text: bindingContext.$data.name }.

Writing a quick custom binding provider

Suppose that we are not satisfied with putting our logic as strings in the data-bind attributes. Maybe our bindings are getting too verbose or they contain more logic than we want in our view. What if we did something similar to CSS classes and explicitly assigned bindings by name to our elements? So, we don’t confuse our presentation classes and our data classes, I am going to assign our binding classes in a data-class attribute.

Our nodeHasBindings function can be pretty simple:

1
2
3
4
//determine if an element has any bindings
function nodeHasBindings(node) {
    return node.getAttribute ? node.getAttribute("data-class") : false;
};

If the node supports the getAttribute function (it is an element), then see if the data-class attribute has a value.

Now we need to write the getBindings function. Like CSS classes, it would be nice to support multiple space-separated classes in a single data-class attribute. This could allow us to share binding specifications between elements.

First let’s take a look at what our bindings will look like. We are going to create an object to hold the bindings. The property names will match the keys that we will use in the data-class attributes. Knockout uses a with statement when parsing bindings that allows variables to be evaluated with the current data context at the top of the scope chain. For these bindings, let’s avoid using with and instead rely on this being set to the current data context when the binding object is returned.

Here are some sample bindings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//our binding object
var bindings = {
    products: {
        foreach: viewModel.products
    },
    nameText: function() {
        return {
            text: this.name
        };
    },
    selectLink: function() {
        return {
            visible: !this.isSelected(),
            click: this.select
        };
    },
};

In the products binding, we can simply return the binding object, as the observableArray that we care about is directly on our view model. In that case, we do not need to rely on this being set correctly. For the other bindings, we return the binding object in an anonymous function where we rely on this being set to the appropriate data. Now we have our bindings specified and we didn’t even need to put them in strings.

The next step is to write our getBindings function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//return the bindings given a node and the bindingContext
function getBindings(node, bindingContext) {
    var result = {};
    var classes = node.getAttribute("data-class");
    if (classes) {
        classes = classes.split(' ');
        //evaluate each class, build a single object to return
        for (var i = 0, j = classes.length; i < j; i++) {
            var bindingAccessor = this.bindingObject[classes[i]];
            if (bindingAccessor) {
                var binding = typeof bindingAccessor == "function" ? bindingAccessor.call(bindingContext.$data) : bindingAccessor;
                ko.utils.extend(result, binding);
            }
        }
    }

    return result;
};

We loop through each key in the data-class attribute and build up a result object from each one. If the binding object is a function, then we call it with our current data as this, otherwise we just use the object that was provided. Currently this handler does not consider the containerless bindings supported in 1.3 that live in comment nodes, but that could be added with some additional work.

Here is what the completed binding provider looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//You can now create a bindingProvider that uses something different than data-bind attributes
ko.customBindingProvider = function(bindingObject) {
    this.bindingObject = bindingObject;

    //determine if an element has any bindings
    this.nodeHasBindings = function(node) {
        return node.getAttribute ? node.getAttribute("data-class") : false;
    };

    //return the bindings given a node and the bindingContext
    this.getBindings = function(node, bindingContext) {
        var result = {};
        var classes = node.getAttribute("data-class");
        if (classes) {
            classes = classes.split(' ');
            //evaluate each class, build a single object to return
            for (var i = 0, j = classes.length; i < j; i++) {
               var bindingAccessor = this.bindingObject[classes[i]];
               if (bindingAccessor) {
                   var binding = typeof bindingAccessor == "function" ? bindingAccessor.call(bindingContext.$data) : bindingAccessor;
                   ko.utils.extend(result, binding);
               }
            }
        }

        return result;
    };
};

The constructor for our binding handler takes in the object used to look up our binidngs. Now, the final step is to tell Knockout to use our custom binding provider (before calling ko.applyBindings) by overriding ko.bindingProvider.instance like this:

1
2
//set ko's current bindingProvider equal to our new binding provider
ko.bindingProvider.instance = new ko.customBindingProvider(bindings);

Now, we can specify bindings in our HTML like:

1
2
3
4
5
6
7
8
9
<div id="list">
    <h2>Product</h2>
    <ul data-class="products">
        <li>
            <a href="#" data-class="nameText selectLink"></a>
            <span class="selected" data-class="nameText selectSpan"></span>
        </li>
    </ul>
</div>

This binding provider sample implementation is available on Github here https://github.com/rniemeyer/knockout-classBindingProvider.

Here is a sample using this technique:

Link to sample on jsFiddle.net

Is this better than the default binding provider?

I personally prefer using declarative bindings in the data-bind attribute, but I think that it is great to have the flexibility to do it in a different way. Even with a technique like this, I still think that it is wise to write a clean and robust view model, possibly using some of the ideas from this post. The view model itself should not change either way. If using a custom binding handler like this one, it is a good idea to keep the object that holds the bindings cleanly separated from the view model.

What else could you do with a custom binding provider?

While the default binding mechanism in Knockout works well for most of us, some developers are looking for alternative ways of specifying their bindings. Some different possibilities for custom binding providers:

  • Use id/class attributes to find bindings in a binding object. Maybe something like Brandom Satrom’s excellent Knockout.Unobtrusive plugin.
  • Store bindings in jQuery $.data or expando properties on the elements (ko.utils.domData.get/set). This would allow you to add bindings directly in code that write to this location. A jQuery plugin could be used to apply bindings to a set of elements.
  • use more specific attributes like data-bind-text and build the bindings based on the attribute name (like Aaron Powell’s KO pre-parser).
  • maybe something with conditional bindings. Based on some state, bindings turn on/off.
  • maybe namespaced bindings where the actual view model applied to the binding depends on the attribute name (like knockout.namespaces).

KO 1.3 Preview Part 1: Native Template Engine

| Comments

Update: Knockout 1.3 was eventually renamed to version 2.0

Knockout 1.3 is coming soon! As it has taken shape over the last couple of months, I have been spending quite a bit of time testing against it and am very excited about the changes that it brings. Steve has a nice rundown of the major changes and a link to 1.3 beta.

I wanted to start a series of short posts highlighting some of the things that I have found interesting and useful in 1.3.

The first thing that is very exciting to me is the inclusion of a native template engine. This means that you can use templates within Knockout without referencing the jQuery Templates plugin or even jQuery. This should be a welcome site to developers that are using alternatives to jQuery or simply want to limit the footprint of their app and its dependencies.

By default, the native template engine supports two kinds of templates. First it supports templates that live within a DOM element. This can be within a script tag or even inside an element of any type (of course that element may get rendered and bound itself). The second type of template that it supports is an anonymous template, which uses the content inside of the element as a template. Anonymous templates are used by the native template engine whenever a name is not passed to the template binding.

The if, ifnot, with, and foreach control flow bindings that Steve describes in his post are actually implemented as shortcuts to the template binding and use anonymous templates. I think that it is helpful to understand how the control flow bindings translate to the template binding. Here are some samples:

The if binding will only render/bind the contents of the element when the condition evaluates to a truthy value.

1
2
3
4
5
6
7
8
9
<div data-bind="if: editMode ">
    <input data-bind="value: name" />
</div>

<!-- equivalent to this -->

<div data-bind="template: { if: editMode }">
    <input data-bind="value: name" />
</div>

The ifnot binding will only render/bind the contents when the condition evaluates to a falsy value.

1
2
3
4
5
6
7
8
9
<div data-bind="ifnot: readOnly ">
    <input data-bind="value: name" />
</div>

<!-- equivalent to this -->

<div data-bind="template: { ifnot: readOnly}">
    <input data-bind="value: name" />
</div>

The with binding will do the same as the if binding, but will also switch the context that the template is bound against to whatever is passed to the binding.

1
2
3
4
5
6
7
8
9
<div data-bind="with: selectedItem">
    <input data-bind="value: name" />
</div>

<!-- equivalent to this -->

<div data-bind="template: { if: selectedItem, data: selectedItem }">
    <input data-bind="value: name" />
</div>

The foreach binding will repeat the contents for each item in the array passed to it.

1
2
3
4
5
6
7
8
9
<ul data-bind="foreach: items">
    <li data-bind="text: name"></li>
</ul>

<!-- equivalent to this -->

<ul data-bind="template: { foreach: items }">
    <li data-bind="text: name"></li>
</ul>

One additional note is that the control-flow bindings do force themselves to be rendered by the native template engine by using the templateEngine parameter of the template binding.

The new control flow bindings definitely ease the burden of having to define many small templates in script tags to handle nested content. Implementing these bindings using the template engine is a great way to reuse code and to make sure that dynamic content is all handled in the same manner. Since templates are generally a necessity when dealing with arrays, it is nice that they can be used without any other references than Knockout itself. I believe that these changes will alter the way that we all write even the simplest of Knockout pages.

Next up: defining a custom binding provider.

All of the KnockoutJS.com Live Samples in jsFiddle

| Comments

Update 5/18/2012 - the fiddles are now up-to-date with Knockoutjs.com and are using KO 2.1

Often in the Knockout.js forums, new users have a desire to play with and modify some of the live examples shown on KnockoutJS.com. Often times, I help users get their sample working in jsFiddle or make a fiddle that they can fork.

I thought that it might be useful to have links to fiddles for all of the currently available samples.

Introductory examples

Detailed examples

Tutorials

  1. Introduction – original - in jsFiddle
  2. Working with Templates and Lists - original - in jsFiddle
  3. Single Page applications – original - in jsFiddle or full page here
  4. Creating custom bindings – original - in jsFiddle
  5. Loading and saving data – original - in jsFiddle

I hope that these links help new Knockout users get something to play with a little faster, after they have read the documentation and completed the tutorials.

Simplifying and Cleaning Up Views in KnockoutJS

| Comments

A common source of discontent that I hear about Knockout.js is how easy it is to find yourself with complex and verbose data-bind attributes that contain logic and code that belongs elsewhere.

Partially because of this issue, there has been interest lately in ways to unobtrusively apply bindings. If a robust solution is developed to handle this, then it may be an interesting option with its own pros and cons. However, I wanted to present another angle on this topic. I believe that there are many techniques that can be used to reduce the complexity and general craziness of the data-bind attributes.

Here are some common examples of bindings that could stand to be improved for various reasons:

data-bind=”enable: items().length < 10”

data-bind=”visible: !hiddenFlag()”

data-bind=”text: selectedItem() ? selectedItem().name() : ‘unknown’”

data-bind=”value: name, event: { focus: function() { viewModel.selectItem($data); }, blur: function() { viewModel.selectItem(null); }”

data-bind=”css: { success: selectedItem().isSaved(), error: !selectedItem().isSaved() }”

data-bind=”click: function() { viewModel.selectItem($data); }”

Let’s look at some ways that we could handle each of these bindings in a cleaner way.

Encapsulating logic in a dependentObservable

Enabling or disabling an element based on a condition is a common scenario. It is not uncommon to see a binding that looks like:

1
<button data-bind="click: addItem, enable: items().length < 10">Add Item</button>

This binding contains a JavaScript expression and it includes a a hard-coded value. We could improve this by pushing the logic to our view model in a computed observable.

1
2
3
4
5
6
7
8
var viewModel = {
  items: ko.observableArray(),
  itemLimit: ko.observable(10)
};

viewModel.addItemsAllowed = ko.computed(function() {
  return this.items().length < this.itemLimit();
}, viewModel);

Now, we can replace the binding with:

1
<button data-bind=”click: addItem, enable: addItemsAllowed>Add Item</button>

The item limit can now even be adjusted on-the-fly and the UI will react appropriately. This concept is also now represented in the view model and can potentially be reused in this view or other views.

Simple custom bindings that wrap existing bindings

It is not uncommon for the view model to contain a boolean that we want to pass to a binding. However, we frequently want to pass the opposite of that boolean based on how the particular binding is coded.

1
<button data-bind="click: editItem, visible: !hiddenFlag()">Edit</button>

Besides changing our data model, one choice in this situation would be to write a computed observable that represents the opposite of this value. However, this may add unnecessary bloat to the view model. Instead, we can easily write a hidden binding that will allow you to pass hiddenFlag directly.

1
2
3
4
5
6
ko.bindingHandlers.hidden = {
  update: function(element, valueAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    ko.bindingHandlers.visible.update(element, function() { return!value; });
  }
};

Now, the binding is simplified to:

1
<button data-bind="click: editItem, hidden: hiddenFlag">Edit</button>

Protecting against null objects

If you have an observable that contains an object and you want to bind to properties of that object, then you need to be careful if there is a chance that it can be null or undefined. You may write your binding like:

1
<span data-bind=”text: selectedItem() ? selectedItem().name() : unknown’”></span>

There are a number of ways to handle this one. The preferred way would be to simply use the template binding:

1
2
3
4
var viewModel = {
   items: ko.observableArray(),
   selectedItem: ko.observable()
};
1
2
3
4
5
6
7
<ul data-bind="template: { name: 'editorTmpl', data: selectedItem }"></ul>

<script id="editorTmpl" type="text/html">
   <li>
     <input data-bind="value: name" />
   </li>
</script>

With this method, if selectedItem is null, then it just won’t render anything. So, you would not see unknown as you would have in the original binding. However, it does have the added benefit of simplifying your bindings, as you can now just specify your property names directly rather than selectedItem().name. This is the easiest solution.

Just for the sake of exploring some options, here are a few alternatives:

You could use a computed observable, as we did before.

1
2
3
4
viewModel.selectedItemName = ko.computed(function() {
  var selected = this.selected();
  return selected ? selected.name() : 'unknown';
}, viewModel);

However, this again adds some bloat to our view model that we may not want and we might have to repeat this for many properties.

You could use a custom binding like:

1
<div data-bind="safeText: { value: selectedItem, property: 'name', default: 'unknown' }"></div>
1
2
3
4
5
6
7
8
9
10
11
12
13
ko.bindingHandlers.safeText = {
  update: function(element, valueAccessor, allBindingsAccessor) {
    var options = ko.utils.unwrapObservable(valueAccessor()),
        value = ko.utils.unwrapObservable(options.value),
        property = ko.utils.unwrapObservable(options.property),
        fallback = ko.utils.unwrapObservable(options.default) || "",
        text;

        text = value ? (options.property ? value[property] : value) : fallback;

        ko.bindingHandlers.text.update(element, function() { return text; });
    }
};

Is this better than the original? I would say probably not. It does avoid the JavaScript in our binding, but it is still pretty verbose.

One other option would be to create an augmented observable that provides a safe way to access properties while still allowing the actual value to be null. Could look like:

1
2
3
4
5
6
7
8
ko.safeObservable = function(initialValue) {
  var result = ko.observable(initialValue);
  result.safe = ko.dependentObservable(function() {
    return result() || {};
  });

  return result;
};

So, this is just an observable that also exposes a computed observable named safe that will always return an empty object, but the actual observable can continue to store null.

Now, you could bind to it like:

1
<div data-bind=”text: selectedItem.safe().name></div>

You would not see the unknown value when it is null, but it at least would not cause an error when selectedItem is null.

I do think that the preferred option would be using the template binding in this case, especially if you have many of these properties to bind against.

Handling multiple events in a custom binding

When attaching methods from our view model to events on our elements, it is not uncommon for the syntax to get unruly, especially if we need to use an anonymous function to pass parameters.

1
<input data-bind="value: name, event: { focus: function() { viewModel.selectItem($data); }, blur: function() { viewModel.selectItem(null); } }" />

In this case, we want to mark this item as selected when someone enters this field and clear the selection when they leave it.

This would be a good spot for a custom binding handler. In fact, the documentation already shows an example of creating a binding that will do this for you and it even supports updates from the selectedItem being set or cleared programmatically.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ko.bindingHandlers.hasFocus = {
    init: function(element, valueAccessor) {
        $(element).focus(function() {
            var value = valueAccessor();
            value(true);
        });
        $(element).blur(function() {
            var value = valueAccessor();
            value(false);
        });
    },
    update: function(element, valueAccessor) {
        var value = valueAccessor();
        if (ko.utils.unwrapObservable(value))
            element.focus();
        else
            element.blur();
    }
};

This would allow you to simplify the binding down to:

1
<input data-bind=”value: name, hasFocus: selectedItem />

Returning a binding object from our view model

1
2
<div data-bind=”css: { success: selectedItem().isSaved, error:
!selectedItem().isSaved() }”>

In this case, we want to add a success class when isSaved is true and an error class when it is false.

One option is to use a computed observable that returns our binding object like:

1
2
3
4
5
6
7
8
9
10
11
viewModel.selectedSaveClass = ko.dependentObservable(function() {
    var result = {},
        item = this.selectedItem();

    if (item) {
       result.success = item.isSaved();
       result.error = !item.isSaved();
    }

    return result;
}, viewModel);

Now, our css binding will always be given a proper object to bind against. In this case, we will likely be sending and receiving the selectedItem itself or the items array, so having this selectedSaveClass on our view model doesn’t interfere with the JSON that we communicate to/from the server. However, in the case that it does, there are a few ways to deal with it. You could override the toJSON() method on your object as described here. Another trick is to place the properties that you don’t want serialized to JSON as sub-observables. For example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var viewModel = {
  selectedItem: ko.observable()
};

viewModel.selectedItem.saveStyle = ko.dependentObservable(function() {
    var result = {},
        item = this.selectedItem();

    if (item) {
       result.success = item.isSaved();
       result.error = !item.isSaved();
    }

    return result;

}, viewModel);

Now, if you do a ko.toJSON(viewModel) or ko.toJSON(selectedItem), you will just get your item and not the style object. The toJSON() method will see that selectedItem is an observable and then unwrap it. It does not look for any properties/observables attached to the observable itself (which is a function). So, this is a nice way to hide values that are not important to send back to the server.

Avoiding anonymous functions in event bindings

update 5/1/2012: in KO 2.0, the data is now passed automatically to click and event handlers as the first argument and the parent scopes are available via $root and $parent. An anonymous function is generally no longer needed for this scenario.

Inside of a template, a common task is to call a method off of a parent object and pass the child object. In Knockout, to pass arguments to a function you need to wrap it in an anonymous function like:

1
<a href="#" data-bind="click: function() { viewModel.selectItem($data); }">Select</a>

There are several approaches that we could use to clean this up.

We could create a custom binding that automatically passes the data. Something like:

1
2
3
4
5
6
7
8
9
10
11
12
ko.bindingHandlers.clickWithData = {
    init: function(element, valueAccessor, allBindingsAccessor, context) {
        var action = valueAccessor(),
        var newValueAccessor = function() {
            return function(event) {
                action.apply(context,[context, event]);
            };
        };

        ko.bindingHandlers.click.init(element, newValueAccessor, allBindingsAccessor, context);
    }
};

If viewModel has global scope, then in your item you can now avoid the anonymous function like:

1
<a href=”#” data-bind=”clickWithData: viewModel.selectItem>Select</a>

If it does not have global scope, then you can pass the function into your child template using the templateOptions parameter.

1
2
3
4
5
6
7
8
<ul data-bind="template: { name: 'itemTmpl', foreach: items, templateOptions: { select: selectItem } ]"></ul>

<script id=”itemTmpl” type=”text/html”>

   <li>
      <a href="#" data-bind="clickWithData: $item.selectItem">Select</a>
   </li>
</script>

Another option that works quite well is to put the selection method on the item itself.

1
2
3
4
5
6
7
8
9
10
11
function Item(id, name, selectedItem) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),

        select: function() {
            selectedItem(this);

        }
    };
}

So, our item does not even need a parent property, we just pass the selectedItem observable into the constructor function and use it inside of the select function. Now, you can simply do:

1
<a href="#" data-bind="click: select">Select</a>

In my opinion, this is the simplest and cleanest option. However, it does take some planning in how the view model is populated, so the selectedItem observable is available to be passed to our Item constructor function.

Final Thoughts

Producing a clean view in Knockout is not always a simple task. It does take some planning and extra considerations in the view model. Custom bindings can make a big difference in simplifying your logic and in many cases they may need to be tailored towards performing a specific task to keep a clean syntax. In the end, you can end up with a clean view, a robust view model, and an array of bindings that can potentially be reused across a site.

Another Look at Custom Bindings for KnockoutJS

| Comments

Custom bindings are a powerful and exciting feature that seem to be often overlooked by newcomers to Knockout.js. They are the key to allowing Knockout to gracefully handle complex behaviors and/or control third-party components/widgets. While there is good documentation on custom bindings here, I wanted to provide an additional perspective on them.

It is easy to get hung up on the custom part of the name custom binding and feel like you are making up for some short-coming in the framework or that it is a “heavyweight” or “complex” solution to a problem that seems simple. However, I feel that custom bindings should be treated as just another tool in your KO toolbox, along with computed observables and manual subscriptions, rather than a last resort that is only turned to after failing to make the default bindings work for a scenario.

In my ideal Knockout application, all of the code that involves accessing and manipulating the DOM in any way is isolated to bindings. So, anything that crosses between your view model and your UI can (and should) be in a binding. Some bindings may not even involve your view model and can just provide a way to declaratively wire up some functionality.

The mechanics of custom bindings

When you define a custom binding, you are able to specify an init and an update function.

1
2
3
4
5
6
7
8
ko.bindingHandlers.myCustomBinding = {
    init: function(element, valueAccessor, allBindingsAccessor, data, context) {
      //init logic
    },
    update: function(element, valueAccessor, allBindingsAccessor, data, context) {
       //update logic
    }
};

The init function will only run the first time that the binding is evaluated for this element. This is usually used to run one-time initialization code or to wire up event handlers that let you update your view model based on an event being triggered in your UI.

The update function provides a way to respond when associated observables are modified. Typically, this is used to update your UI based on changes to your view model. It is important to understand the three cases where the update function can be called:

  1. Initially when the binding is first evaluated (after the init function)
  2. Any time that an observable changes that was accessed as part of the the previous execution of the update function for this binding. Bindings are implemented internally using computed observables, so any observables that have their value accessed create dependencies for the binding.
  3. Any time that another binding in the same data-bind attribute is triggered. This helps ensure things like the value is appropriate when the options are changed.

The init and update functions are supplied four arguments. Generally, you will want to focus on the element and the valueAccessor parameters, as they are the standard way to link your view model to your UI.

  • element - this gives you direct access to the DOM element that contains the binding. In this paradigm, you have no real need to give these elements ids, names, or classes for the purpose of selecting/locating them (unless you need to for other reasons).
  • valueAccessor - this is a function that gives you access to what was passed to the binding. If you passed an observable, then the result of this function will be that observable (not the value of it). If you used an expression in the binding, then the result of the valueAccessor will be the result of the expression.
  • allBindingsAccessor - this gives you access to all of the other bindings that were listed in the same data-bind attribute. This is generally used to access other bindings that interact with this binding. These bindings likely will not have any code associated with them and are just a way to pass additional options to the binding, unless you choose to pass an object with multiple properties into your main binding. For example, optionsValue, optionsText, and optionsCaption are bindings that are only used to pass options to the options binding.
  • data - For bindings outside of templates, this will provide access to your overall view model. Inside of a template, this will be set to the data being bound to the template. For example, when using the foreach option of the template binding, the viewModel parameter would be set to the current array member being sent through the template. Most of the time the valueAccessor will give you the data that you want, but the viewModel parameter is particularly useful if you need an object to be your target when you call/apply functions.
  • context - This is the binding context which includes properties like $data, $parent, $parents, and $root. Documentation about each property available can be found here.

Common scenarios

1- Simple initialization

In a case where you just want to declaratively run some code against an element, you can use a simple init. For example, if you want to hook up a jQuery UI button, it might look like:

1
2
3
4
5
6
ko.bindingHandlers.jqButton = {
    init: function(element, valueAccessor) {
        var options = valueAccessor() || {};
        $(element).button(options);
    }
};

You would declare it like:

1
<button data-bind="click: greet, jqButton: { icons: { primary: 'ui-icon-gear' } }">Test</button>

Sample here: http://jsfiddle.net/rniemeyer/Rn9tg/

2- Run some code against an element when an observable changes

Suppose we want to make an element flash whenever a certain observable changes. We could do something like:

1
2
3
4
5
6
ko.bindingHandlers.flash= {
    update: function(element, valueAccessor) {
        ko.utils.unwrapObservable(valueAccessor());  //unwrap to get subscription
        $(element).hide().fadeIn(500);
    }
};

Notice that we try to unwrap the value passed to us, in case it is an observable, but we do not even keep track of the value. This is simply to create a dependency in our binding on that observable.

Sample here: http://jsfiddle.net/rniemeyer/s3QTU/

3- Simple wrapper binding

One of the easiest types of binding to start with is one that simply “wraps” an existing binding. For example, suppose you want some text to fade in when it changes. The text binding already handles updating the element properly (and is presumably well-tested against various browsers) and we just want to add some animation to it. So, we can write a simple wrapper to the text binding that looks like:

1
2
3
4
5
6
7
ko.bindingHandlers.fadeInText = {
    update: function(element, valueAccessor) {
        $(element).hide();
        ko.bindingHandlers.text.update(element, valueAccessor);
        $(element).fadeIn();
    }
};

Sample here: http://jsfiddle.net/rniemeyer/SmkpZ/

4- Wrapper that forwards a modified valueAccessor

Another example of a “wrapper” binding is when you want to intercept the value passed to the binding and modify it before passing it on to a default binding. Suppose, we want to create a modified click binding that allows us to pass an array of parameters to it, rather than being forced to use an anonymous function.

1
2
3
4
5
6
7
8
9
10
11
ko.bindingHandlers.clickWithParams = {
    init: function(element, valueAccessor, allBindingsAccessor, data, context) {
        var options = valueAccessor();
        var newValueAccessor = function() {
            return function() {
                options.action.apply(data, options.params);
            };
        };
        ko.bindingHandlers.click.init(element, newValueAccessor, allBindingsAccessor, data, context);
    }
};

You would then use this by passing a function as the action property and an array of parameters as the params property of the object passed to the binding. The binding then builds a new valueAccessor parameter to pass to the click binding.

1
<a href="#" data-bind="clickWithParams: { action: $item.select, params: [ $data ] }">select</a>

Sample here: http://jsfiddle.net/rniemeyer/NkqmK/

5- Two-way binding that needs to broker getting/setting data with a 3rd party control

Suppose we want to bind to a third-party control that exposes APIs for reading and writing values to it. For example, the jQuery UI datepicker control allows us to set its value using a Date object and retrieve that Date object from it rather than dealing with strings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ko.bindingHandlers.datepicker = {
    init: function(element, valueAccessor, allBindingsAccessor) {
        //initialize datepicker with some optional options
        var options = allBindingsAccessor().datepickerOptions || {};
        $(element).datepicker(options);

        //handle the field changing
        ko.utils.registerEventHandler(element, "change", function () {
            var observable = valueAccessor();
            observable($(element).datepicker("getDate"));
        });

        //handle disposal (if KO removes by the template binding)
        ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
            $(element).datepicker("destroy");
        });

    },
    //update the control when the view model changes
    update: function(element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        $(element).datepicker("setDate", value);
    }
};

You would use the binding like:

1
<input data-bind="datepicker: myDate, datepickerOptions: { minDate: new Date() }" />

This custom binding handles three aspects of working with the jQuery UI datepicker control:

  1. initializing the control (with optional config options for the widget)
  2. responding to updates made in the UI by setting up an event handler
  3. responding to updates made to the view model.

These are the typical scenarios that would need to be handled when dealing with an editable control.

Sample here: http://jsfiddle.net/rniemeyer/X82aC/

A quick note about bindings that write to non-observables

Knockout supports binding editable controls to non-observables (plain properties). In this case, edits to the field do write to the underlying values, but nobody is notified. To properly set a non-observable property on your view model, Knockout provides a setter function via an additional binding, as it would not have a way to pass the property by reference. This is only available for primitive types. For a binding that requires multiple options, if you need to support writing to a non-observable, then this may be a reason to provide options by additional bindings rather than by passing an object literal.

Final thoughts

Custom bindings make Knockout.js capable of easily and elegantly controlling complex behaviors. While it is great to create generic, reusable bindings, they can also be used to just simplify your code by combining multiple actions into a single binding or setting default options/logic in a binding rather than using overly complicated data-bind attributes. Once you start writing custom bindings, you will quickly see that they unlock a whole new world of possibilities!