Custom MVVM binders are a powerful part of the Kendo UI MVVM framework. Making basic
However, you have likely used the built-in Kendo bindings that use complex binding paths or objects. For example, the events
and attr
bindings:
<div data-bind="events: { click: onClick, mouseover: onMouseOver, mouseout: onMouseOut }">
If you have tried to make a binder like this yourself, you have probably run into issues. Kendo actually does not provide support for these complex bind paths for custom binders. The ones that are built into Kendo are handled differently internally, letting them work correctly. However, there is a way we can make them work with a little extra effort.
For this example, we are going to make a custom binder that adds/removes CSS classes from the target element. This will be done using jQuery’s .addClass()
and .removeClass()
functions so that it will not clobber any existing classes defined on the element. Our desired syntax will be:
<div data-bind="class: { name-of-class: value, name-of-another-class: value, ... }">
So the left side of the colon will be the name of the class, and the right side will be the value to check. If the value is
We can start by defining the basic code for the custom binder:
kendo.data.binders.class = kendo.data.Binder.extend({ init: function (target, bindings, options) { kendo.data.Binder.fn.init.call(this, target, bindings, options); }, refresh: function () { } });
So, the big reason that Kendo doesn't appear to play nicely with custom complex bindings is that in the refresh function you will want to call: this.bindings.class.get()
to get the value of the binding path (the part on the right of the colon). However, Kendo expects this to be a string representation of a variable or function name. So if our custom binding was simply data-bind="class: getClassName"
then the call to .get()
would try to find the value of a property or function named "getClassName"
however in our complex example, the .get()
function doesn’t know how to return a value for "{ name-of-class: value, name-of-another-class: value }"
because it doesn't define a single path to a single piece of data.
What we need to do is actually call this.bindings.class.get() multiple times, one for each of the properties (class names) of our complex binding type. The .get() function looks in the binding object’s path property to get this path string. We just need to set it each time.
OK, so, to do this, we need to start by adding some code to our binder’s .init()
constructor function to look at our complex binding path, and get a list of all the ‘keys’ (the class names).
kendo.data.binders.class = kendo.data.Binder.extend({ init: function (target, bindings, options) { kendo.data.Binder.fn.init.call(this, target, bindings, options); // get list of class names from our complex binding path object this._lookups = []; for (var key in this.bindings.class.path) { this._lookups.push({ key: key, path: this.bindings.class.path[key] }); } }, refresh: function () { } });
So if your example binding HTML is:
<div data-bind="class: { selected: isSelected, error: hasError }">
then what we just built and stored in _lookups
is:
[ { key: selected, path: isSelected }, { key: error, path: hasError } ]
Now in our .refresh()
function, we want to loop over the items in our _lookups
array. For .get()
function. Then we can act on each of them.
kendo.data.binders.class = kendo.data.Binder.extend({ init: function (target, bindings, options) { kendo.data.Binder.fn.init.call(this, target, bindings, options); // get list of class names from our complex binding path object this._lookups = []; for (var key in this.bindings.class.path) { this._lookups.push({ key: key, path: this.bindings.class.path[key] }); } }, refresh: function () { var lookup, value; for (var i = 0; i < this._lookups.length; i++) { lookup = this._lookups[i]; // set the binder's path to the one for this lookup, // because this is what .get() acts on. this.bindings.class.path = lookup.path; value = this.bindings.class.get(); // add or remove CSS class based on if value is truthy if (value) { $(this.element).addClass(lookup.key); } else { $(this.element).removeClass(lookup.key); } } } });
So there we have it! A fully functional, very useful custom Kendo binder that uses a complex binding path! Download Kendo UI and discover the power of the MVVM binding framework in your web and mobile applications.
Jeff Valore enjoys promoting Software Craftsmanship at local user