Having trouble viewing Cygnet-Infotech Site® ? It's because the browser you are using is not supported. Please upgrade to one of the latest versions.

Introduction to Knockout Custom Binding Handlers

Cygnet Infotech

Knockout JS (commonly known as KO) is a great JavaScript Library that works on top of your web application on any mainstream browser. It helps creating rich, responsive and interactive UIs using MVVM (Model-View-View-Model) pattern with a clean underlying data-model. It is compact and is suitable for any Server or Client-side technology.
Knockout JS is known for its dynamic architecture that enables a UI to update on itself automatically. It comes with lots of bindings that enable ‘Declarative Binding’ using ‘Observable ViewModel’ on the client (browser) that helps implement changes automatically when the data source of any UI changes as a result of user intervention. Hence, for any UI changes or manipulations in the DOM elements, Knockout JS has inbuilt bindings that handle the inconsistencies without complexities and chaos.
Some of the readily available bindings of KO are ‘foreach,’ ‘text’, ‘html’, ‘visible’ etc. However, sometimes readily available bindings are not enough to use them as it is. Especially, when you have got third-party JavaScript library which you need to integrate and for which you need to write UI update code.
Hmm! That’s where you require to create your own bindings, i.e. Custom Bindings.

Custom Bindings Handlers in Knockout JS

KO provides this sophisticated way to gracefully handle complex behaviors of third-party widgets/components.
Here’s how

ko.bindingHandlers.myBinding = {
init: function(element, valueAccessor, allBindings, data, bindingContext) {
// this will be called first time only when the binding is evaluated for the element
},
update: function(element, valueAccessor, allBindings, data, bindingContext) {
// this will be called once when the binding is first time applied to the element and then again when associated observables are modified
}
};

  • element – DOM element. The element on which the binding is applied.
  • valueAccessor – returns the bound value of the element. Sometimes it may be a value and sometimes an observable.
  • allBindings – an object that provides access to all the model values bound to the element.
  • data – return view model
  • bindingContext – This is an object that holds the binding context of the element as $parent, $data etc.

A detailed description for Custom Bindings can be viewed at Custom bindings with Knockout
In this tutorial, I am going to present a couple of simple binding handlers that can make HTML elements binding pretty easy to deal with!

A) Common HTML Element Bindings

1) Image: src attribute

It is pretty common to bind <img/> tags, but becomes annoying to use attr binding handler. This is the shortcut to get a cleaner syntax.

It will look like:


ko.bindingHandlers.src = {
update: function (element, valueAccessor) {
ko.bindingHandlers.attr.update(element, function () {
return {
src: valueAccessor()
};
});
}
};

It is declared as:


< img data-bind="src: $data.myImage" / >

Instead of:

< img data-bind=”attr: {src: $data.myImage }” / >

Sample here: http://jsfiddle.net/CygnetInfotech/vybnerbo/

2) Styling: margin, alignment

Styling is a major aspect in the HTML world and providing inline styles is a common practice (though not recommended!). What if it becomes easier to bind inline styles with a simple syntax?

Here it goes:


ko.bindingHandlers.setStyle = {
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
ko.bindingHandlers.style.update(element, function () {
return {
margin: ko.unwrap(valueAccessor()),
textAlign: allBindingsAccessor().textAlign
};
}, allBindingsAccessor, viewModel, bindingContext);
}
};

It is declared as:

<div id="content" data-bind="setStyle: $data.margin, textAlign: $data.alignment">
</div>

Instead of:

<div id=”content” data-bind=”style: {margin: 10px, textAlign: center}”>
</div>

Sample here: http://jsfiddle.net/CygnetInfotech/fo1o1bkm/

3) Toggle

This tiny piece of code can really help reduce some clutter in viewmodels. Often times, it is required to bind a click handler only for setting the visibility (show/hide) of HTML elements.

ko.bindingHandlers.toggle = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
//unwrap value
var value = valueAccessor();
ko.applyBindingsToNode(element, {
click: function () {
value(!value());
}
});
}
};

It can be declared as:

<button data-bind="toggle: isHidden">Show/Hide</button>

Instead of:


<button data-bind="click: function(){isHidden(!isHidden());}">Show/Hide</button>

Sample here: http://jsfiddle.net/CygnetInfotech/yfr80f91/

B) Knockout Utility Function Binding

1) toJSON

Knockout has a number of utility functions used by the library itself. One such example is ko.toJSON. It can be used to quickly bind entire view model (having both observable and non-observable properties) that can be passed to an Ajax call directly and quickly see all changes going on.

ko.bindingHandlers.toJSON = {
update: function (element, valueAccessor) {
return ko.bindingHandlers.text.update(element, function () {
return ko.toJSON(valueAccessor(), null, 2);
});
}
};

It can be declared as:

< pre data-bind="toJSON: $data" > < /pre >

Instead of:

< pre data-bind="text: ko.toJSON($data)" > < / pre >

Sample here: http://jsfiddle.net/CygnetInfotech/r1sL2ngc/

C) Third Party Controls: jQuery UI controls bindings

1) Date Picker
Binding to a third-party control for example, jQuery UI datepicker control! This could be all the way easy to allow the control to deal with Date object instead of working with strings.

ko.bindingHandlers.datepicker = {
init: function (element, valueAccessor, allBindingsAccessor) {
//initialize date picker
var options = allBindingsAccessor().datepickerOptions || {};
$(element).datepicker(options);
//handle change
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: function (element, valueAccessor) {
var value = ko.unwrap(valueAccessor()),
current = $(element).datepicker("getDate");

if (value - current !== 0) {
$(element).datepicker("setDate", value);
}
}
};

It can be declared as:

< input data-bind="datepicker: currentDate, datepickerOptions: { minDate: new Date(), dateFormat: 'mm/dd/yy' }" / >

Sample here: http://jsfiddle.net/CygnetInfotech/qsqc11fu/

2) jQuery dialog
One of the most widely used features in a JS-based web application is dialog. Often we encounter issues. For example, on closing a dialog, the KO bindings are not released properly, which leads to random UI behavior in which it doesn’t show the refreshed content, even when the dialog is opened and closed multiple times and at last leads to a hair scratching situation!

Aghast..!!! But wait, what if we leave all the dialog bindings to knockout itself only?

Here it shows how:

ko.bindingHandlers.jqDialog = {
init: function (element, valueAccessor) {
var options = ko.unwrap(valueAccessor()) || {}; //handle disposal
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).dialog("destroy");
});

$('.ui-dialog-content[id]').each(function () {
if (element.id == this.id) {
$(this).dialog("destroy").remove();
}
});
$(element).dialog(options);
}
};

It can be declared as:

< div id="HelloDialogId" title="Hello Dialog" data-bind="jqDialog: {height: 100, width: 200, modal: true, draggable: true, resizable: false, autoOpen: false,
close: function () { isOpen(false) }},
openDialog: isOpen" >
< p > Hello! < / p >
< / div >

Description:

jqDialog: It is the custom binding handler that allows to define jQuery dialog’s syntax in a simple and easy manner.

openDialog: It is the custom binding handler that handler open/close of the dialog on the basis of isOpen flag. When the value for isOpen is set to true, the dialog is opened and when set to false the dialog is closed.

The fiddle in the example also covers another binding handler for jQuery buttons. It is defined as:

ko.bindingHandlers.jqButton = {
init: function (element, valueAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
//handle disposal
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).button("destroy");
});
$(element).button(options);
}
};

It is declared as:

< button data-bind="click: clickMe, jqButton: { icons: { primary: 'ui-icon-tag' } }" > Click Me! < / button >

Sample here: http://jsfiddle.net/CygnetInfotech/Lnr12bk6/

3) Loader

Any operation which is long running or requires server interaction needs a loading mask to be applied to UI in order to restrict users from making subsequent calls. The same can be handled through custom binding, making it more maintainable code (as it can be required in multiple pages depending upon the UI implementation)

ko.bindingHandlers.loader = {
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var value = valueAccessor(),
//$element = $(element),
valueUnwrapped = ko.utils.unwrapObservable(value),
loadingMsg = allBindingsAccessor().loaderMsg,
loadingElementId = allBindingsAccessor().loaderElement,
$element = $('#' + loadingElementId);
if (valueUnwrapped) {
//load Mask
$element.mask(loadingMsg);
} else {
//hide mask
$element.unmask();
}
}
};

It can be declared as:

< div id="loadMaksContents" >
< div data-bind="loader: isBusy, loaderMsg: loaderMsg, loaderElement: 'loadMaksContents' >
< / div >
< / div >

Description:

loader: This is the custom binding handler that works on ‘isBusy’ boolean flag that controls the loading and unloading of the mask based on the flag value
loaderMsg: this is the binding attribute that specifies the message to be displayed in load mask
loaderElement: This is the binding attribute that specifies the id of the element upon which loading mask is to be applied

Sample here: http://jsfiddle.net/CygnetInfotech/qzfz69ch/

That’s all from my side. Hope you explore amazing possibilities in your development endeavors with these custom binding handlers ?

Created and Compiled by:
Surbhi Mahnot

Cygnet Infotech

Cygnet Infotech is a CMMi level 3 and is ISO 27001:2013 and ISO 9001:2008 certified, 18 year old global technology provider enabling ISVs & enterprises through emerging technology, software engineering, technology consulting, SAP Implementation, advisory & maintenance services. It’s proven 18-year track record boasts of successfully delivered 1400+ valuable software solutions to its diverse clientele across the globe using a global delivery model.

View All Posts
comments powered by Disqus

Get started with Cygnet

Cygnet may keep me informed via email or phone about its Products and Services.