The kendo.init
and kendo.bind
methods in Kendo UI are very similar. So much so, that it might leave you wondering "Why are there two methods for initializing the HTML, and which one should I use"?
That's why we're here today to say: Stop using init
. The bind
method is preferred.
Let's take a look at what each of these do, and why you should use bind
in favor of init
.
Since launching Kendo UI just over two years ago, we have added two very important features into the core framework.
The order in which I listed those is paramount, because it's going to help explain why there are two different ways to initialize Kendo UI widgets and two different kinds of data
syntax. You will notice that declarative initialization and MVVM are not either-or patterns, but rather are a very powerful combination.
There are generally two ways to create a Kendo UI widget: Imperative or Declarative. Let's look at a simple sample.
This code should look relatively familiar if you have used any sort of jQuery plugin before. The flow is simple and is one of the reasons why we love jQuery so darn much.
This is known as "Imperative Initialization". Or sometimes called "jQuery Initialization". Kendo UI follows standard jQuery plugin best practices and all Kendo UI widgets can be created this way. The great thing about jQuery Initialization is that it works the same everywhere. If you have ever used any jQuery plugin, you already know how to use Kendo UI.
While we were working on Kendo UI, we were also working on the project now known as Icenium. The engineers working on that team were using Kendo UI to build the Mist IDE. They asked if we would consider including "Declarative Initialization" in Kendo UI. We thought it was a good idea, and thus the second ever release of Kendo UI included the ability to initialize widgets declaratively.
But what exactly is declarative initialization?
The idea with declarative initialization is that HTML is more than capable of giving your JavaScript UI framework (in this case Kendo UI) the information that it needs to both initialize and configure a widget. Think about it: Kendo UI can make any valid <div>
element on that page into a color palette. It just wants to know which one. Wouldn't it be better if the element you wanted to transform sort of raised it's hand and said to Kendo UI, "PICK ME!". This is how declarative initialization works, and it is facilitated by HTML5 data attributes.
A widget can be defined simply by specifying a data-role
.
<div id="colors" data-role="colorpalette"></div>
The configuration can also be moved into the markup since any data
attribute is valid and available for us to use. That means the entire color palette configuration can go into the markup. This includes any functions that you want to call from widget events. In declarative initialization, these functions must be accessible of the window object.
<div id="colors" data-role="colorpalette" data-columns="4" data-tile-size="{ width: 34, height: 19 }" data-change="window.app.preview"></div> <h3 id="hex">Select A Color</h3> <script> // declare a new top level app variable window.app = {}; // attach a new function to the app object window.app.preview = function(e) { $("#hex").html(e.value); } </script>
Now in order to make all of this work, we needed to add a method to the Kendo UI Core which would take in a piece of the page and parse it for all these data
roles and configuration values. We implemented this as the kendo.init
method. It takes in a selector and initializes that element and all it's children based on it's data
configuration. Usually, we just pass the entire page (document.body), but you can restrict the surface area that Kendo UI has to parse by specifying the lowest top level element.
<div id="wrapper"> <div id="colors" data-role="colorpalette" data-columns="4" data-tile-size="{ width: 34, height: 19 }" data-change="app.preview"></div> <h3 id="hex">Select A Color</h3> </div> <script> // declare a new top level app variable window.app = {}; // attach a new function to the app object window.app.preview = function(e) { $("#hex").html(e.value); }; // initialize any widgets in the #wrapper div kendo.init("#wrapper"); </script>
Shortly after the initial release of the declarative framework, we began implementing the MVVM pattern for Kendo UI. This was a very tricky endeavor for the engineering team. We wanted to give people a familiar API (ala Knockout), but squeeze out every last ounce of speed possible when observing changes and watching both the HTML and JavaScript objects.
This gave birth to the kendo-bind
method. The bind
method is quite similar to init
, except that it takes a second parameter in the form of a kendo.observable
view model.
We decided to implement an observable object where any and all properties would be observable. This would save the developer from having to explicitly specify each and every bound property as such.
In order to specify in the HTML which properties were bound, we parse the data-bind
attribute. This provides a huge speed boost for Kendo UI since it ONLY has to traverse the data-bind
attributes to create the bindings. It also doesn't step on people who are using declarative initialization but not MVVM. It essentially allowed both worlds to exist either together, or separate.
For instance, in our running example, instead of having a function attached to the window (global object), we can bind it to a view model function. The <h3>
is simply bound to a view model property which the change event updates using the set
method of the view model.
<div id="wrapper"> <div id="colors" data-role="colorpalette" data-columns="4" data-tile-size="{ width: 34, height: 19 }" data-bind="events: { change: change }"></div> <h3 id="hex" data-bind="html: hex">Select A Color</h3> </div> <script> // create a new view model var viewModel = kendo.observable({ hex: "Select A Color", change: function(e) { // set the 'hex' field on the view model // to the selected color this.set("hex", e.value); } }); // bind the HTML to the view model kendo.bind("#wrapper", viewModel); </script>
You can see that MVVM is really a combination of both declarative initialization and the two way binding we typically associate with the MVVM pattern. In this second example, bind is doing declarative initialization and then binding the relevant HTML to the view model. MVVM really works in concert with declarative markup.
In the underlying code for Kendo UI, both bind
and init
call kendo.initWidget
which does the declarative initialization. The bind
method then goes on to apply MVVM bindings, but ONLY if you supply a second parameter. This means that bind
and init
are identical in function when supplying only an element selector.
To save yourself from confusion, stop using init
and just use bind
.
It's Ok! We are too in some places. I personally sometimes use one and sometimes the other, when really I could just be using bind
everywhere. It can cause some confusion to see both init
and bind
when you are first getting your feet wet with Kendo UI MVVM. Sticking to just bind
should provide greater consistency throughout your code, and hopefully will also reduce some confusion that may come from using both.
Burke Holland is a web developer living in Nashville, TN and was the Director of Developer Relations at Progress. He enjoys working with and meeting developers who are building mobile apps with jQuery / HTML5 and loves to hack on social API's. Burke worked for Progress as a Developer Advocate focusing on Kendo UI.