bx

Creating Knockout JS Custom Bindings

Understanding Custom Binding

Custom bindings in Knockout JS are one of those essential concepts you need to understand if you want to go beyond the limits of what Knockout provides out of the box. I’ve used them in projects to implement animated transitions or integrate third party plugins. At the end of this post you will find a few demos and examples of how I’ve used bindings.

I guess the first thing you need to understand about the concept of custom bindings is that it they are there to integrate external behaviours into the knockout pattern. What this means is that it allows you control what happens in the UI when an observable has changed and vice versa

Starting Off

Below is a an example of a blank template you would start off with. The bindings only need to registered once after you’ve loaded Knockout.

ko.bindingHandlers.customBindingName = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here
    },
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        // This will be called once when the binding is first applied to an element,
        // and again whenever any observables/computeds that are accessed change
        // Update the DOM element based on the supplied values here.
    }
};

The Example

For the purpose of this post, I will use creating a SlideTransition binding as an example. This binding will work similarly to how the built in visible binding operates. The element will slide down when the observable is set to true and slide up when set to false.

init – This is where we want to set the initial state of the element. Seeing that this is triggered on the initial binding of the page, we do not want see the element sliding up or down, so we will make this behave like the inbuilt visibility binding by just hiding or showing the element.

update – This is triggered when any associated observables are changed. We want to put in the logic for sliding up and down in this section.

ko.bindingHandlers.slideTransition = {
    init: function (element, valueAccessor) {
        // Firstly we safely unwrap the observable
        var data = ko.utils.unwrapObservable(valueAccessor());
        var visible = data;

        // Check if we are passing through just the
        // observable or an object with additional options
        if (typeof data === 'object')
            visible = ko.utils.unwrapObservable(data.visible);

        // Show or hide element
        $(element).toggle(visible);
    },
    update: function (element, valueAccessor) {
        // Firstly we safely unwrap the observable
        var data = ko.utils.unwrapObservable(valueAccessor());

        var visible = data;
        var options;

        // Check if we are passing through just the
        // observable or an object with additional options
        if (typeof data === 'object') {
            visible = ko.utils.unwrapObservable(data.visible);

            if (data.hasOwnProperty('options'))
                options = data.options;
        }

        // If visible slide down else slide up
        if (visible) {
            $(element).stop(true, false).slideDown(options);
        } else {
            $(element).stop(true, false).slideUp(options);
        }
    }
};

Implementation

<!-- Basic implementation -->
<div data-bind="slideTransition: show">
    ... content
</div>

<!-- Advanced implementation with defined duration -->
<div data-bind="slideTransition: { visibility: show, options: { duration: 500 } }">
    ... content
</div>

Conclusion

This is quite a basic example of what you can do, but keep in mind that you could virtually use custom bindings for whatever you want. You could use it to format a date or integer in certain way, animate an element as I demonstrated or incorporate a third party plugin like a date picker to an input field.

Example Code

demo

github

Useful Links

http://knockoutjs.com/documentation/custom-bindings.html

⇺ back