The Kendo MVVM Framework

Exclusive offer: get 50% off this eBook here
Learning Kendo UI Web Development

Learning Kendo UI Web Development — Save 50%

An easy-to-follow practical tutorial to add exciting features to your web pages without being a JavaScript expert with this book and ebook

$26.99    $13.50
by John Adams | September 2013 | Web Development

In this article by John Adams, author of Learning Kendo UI Web Development, we will cover the following topics:

  • Basics of MVVM

  • Simple data binding

  • Creating the view

  • Creating the Model and View-Model

  • Observable data binding

  • Adding data dynamically

  • Data-bind properties for Kendo MVVM

(For more resources related to this topic, see here.)

Understanding MVVM – basics

MVVM stands for Model ( M ), View ( V ), and View-Model ( VM ). It is part of a family of design patterns related to system architecture that separate responsibilities into distinct units. Some other related patterns are Model-View-Controller ( MVC ) and Model-View-Presenter ( MVP ). These differ on what each portion of the framework is responsible for, but they all attempt to manage complexity through the same underlying design principles. Without going into unnecessary details here, suffice it to say that these patterns are good for developing reliable and reusable code and they are something that you will undoubtedly benefit from if you have implemented them properly. Fortunately, the good JavaScript MVVM frameworks make it easy by wiring up the components for you and letting you focus on the code instead of the "plumbing".

In the MVVM pattern for JavaScript through Kendo UI, you will need to create a definition for the data that you want to display and manipulate (the Model), the HTML markup that structures your overall web page (the View), and the JavaScript code that handles user input, reacts to events, and transforms the static markup into dynamic elements (the View-Model). Another way to put it is that you will have data (Model), presentation (View), and logic (View-Model).

In practice, the Model is the most loosely-defined portion of the MVVM pattern and is not always even present as a unique entity in the implementation. The View-Model can assume the role of both Model and View-Model by directly containing the Model data properties within itself, instead of referencing them as a separate unit. This is acceptable and is also seen within ASP.NET MVC when a View uses the ViewBag or the ViewData collections instead of referencing a strongly-typed Model class. Don't let it bother you if the Model isn't as well defined as the View-Model and the View. The implementation of any pattern should be filtered down to what actually makes sense for your application.

Simple data binding

As an introductory example, consider that you have a web page that needs to display a table of data, and also provide the users with the ability to interact with that data, by clicking specifically on a single row or element. The data is dynamic, so you do not know beforehand how many records will be displayed. Also, any change should be reflected immediately on the page instead of waiting for a full page refresh from the server. How do you make this happen?

A traditional approach would involve using special server-side controls that can dynamically create tables from a data source and can even wire-up some JavaScript interactivity. The problem with this approach is that it usually requires some complicated extra communication between the server and the web browser either through "view state", hidden fields, or long and ugly query strings. Also, the output from these special controls is rarely easy to customize or manipulate in significant ways and reduces the options for how your site should look and behave. Another choice would be to create special JavaScript functions to asynchronously retrieve data from an endpoint, generate HTML markup within a table and then wire up events for buttons and links. This is a good solution, but requires a lot of coding and complexity which means that it will likely take longer to debug and refine. It may also be beyond the skill set of a given developer without significant research. The third option, available through a JavaScript MVVM like Kendo UI, strikes a balance between these two positions by reducing the complexity of the JavaScript but still providing powerful and simple data binding features inside of the page.

Creating the view

Here is a simple HTML page to show how a view basically works:

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>MVVM Demo 1</title> <script src ="/Scripts/kendo/jquery.js"></script> <script src ="/Scripts/kendo/kendo.all.js"></script> <link href="/Content/kendo/kendo.common.css" rel="stylesheet" /> <link href="/Content/kendo/kendo.default.css" rel="stylesheet" /> <style type="text/css"> th { width: 135px; } </style> </head> <body> <table> <caption>People Data</caption> <thead> <tr> <th>Name</th> <th>Hair Color</th> <th>Favorite Food</th> </tr> </thead> <tbody data-template="row-template" data-bind="source: people"></tbody> </table> </body> </html>

Here we have a simple table element with three columns but instead of the body containing any tr elements, there are some special HTML5 data-* attributes indicating that something special is going on here. These data-* attributes do nothing by themselves, but Kendo UI reads them (as you will see below) and interprets their values in order to link the View with the View-Model. The data-bind attribute indicates to Kendo UI that this element should be bound to a collection of objects called people.

The data-template attribute tells Kendo UI that the people objects should be formatted using a Kendo UI template. Here is the code for the template:

<script id="row-template" type="text/x-kendo-template"> <tr> <td data-bind="text: name"></td> <td data-bind="text: hairColor"></td> <td data-bind="text: favoriteFood"></td> </tr> </script>

This is a simple template that defines a tr structure for each row within the table. The td elements also have a data-bind attribute on them so that Kendo UI knows to insert the value of a certain property as the "text" of the HTML element, which in this case means placing the value in between <td> and </td> as simple text on the page.

Creating the Model and View-Model

In order to wire this up, we need a View-Model that performs the data binding. Here is the View-Model code for this View:

<script type="text/javascript"> var viewModel = kendo.observable({ people: [ {name: "John", hairColor: "Blonde", favoriteFood: "Burger"}, {name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"}, {name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad"} ] }); kendo.bind($("body"), viewModel); </script>

A Kendo UI View-Model is declared through a call to kendo.observable() which creates an observable object that is then used for the data-binding within the View. An observable object is a special object that wraps a normal JavaScript variable with events that fire any time the value of that variable changes. These events notify the MVVM framework to update any data bindings that are using that variable's value, so that they can update immediately and reflect the change. These data bindings also work both ways so that if a field bound to an observable object variable is changed, the variable bound to that field is also changed in real time.

In this case, I created an array called people that contains three objects with properties about some people. This array, then, operates as the Model in this example since it contains the data and the definition of how the data is structured. At the end of this code sample, you can see the call to kendo.bind($("body"), viewModel) which is how Kendo UI actually performs its MVVM wiring. I passed a jQuery selector for the body tag to the first parameter since this viewModel object applies to the full body of my HTML page, not just a portion of it.

With everything combined, here is the full source for this simplified example:

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>MVVM Demo 1</title> <scriptsrc ="/Scripts/kendo/jquery.js"></script> <scriptsrc ="/Scripts/kendo/kendo.all.js"></script> <link href="/Content/kendo/kendo.common.css" rel="stylesheet" /> <link href="/Content/kendo/kendo.default.css" rel="stylesheet" /> <style type="text/css"> th { width: 135px; } </style> </head> <body> <table> <caption>People Data</caption> <thead> <tr> <th>Name</th> <th>Hair Color</th> <th>Favorite Food</th> </tr> </thead> <tbody data-template="row-template" data-bind="source: people"></tbody> </table> <script id="row-template" type="text/x-kendo-template"> <tr> <td data-bind="text: name"></td> <td data-bind="text: hairColor"></td> <td data-bind="text: favoriteFood"></td> </tr> </script> <script type="text/javascript"> var viewModel = kendo.observable({ people: [ {name: "John", hairColor: "Blonde", favoriteFood: "Burger"}, {name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"}, { name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad" } ] }); kendo.bind($("body"), viewModel); </script> </body> </html>

Here is a screenshot of the page in action. Note how the data from the JavaScript people array is populated into the table automatically:

Even though this example contains a Model, a View, and a View-Model, all three units appear in the same HTML file. You could separate the JavaScript into other files, of course, but it is also acceptable to keep them together like this. Hopefully you are already seeing what sort of things this MVVM framework can do for you.

Observable data binding

Binding data into your HTML web page (View) using declarative attributes is great, and very useful, but the MVVM framework offers some much more significant functionality that we didn't see in the last example. Instead of simply attaching data to the View and leaving it at that, the MVVM framework maintains a running copy of all of the View-Model's properties, and keeps references to those properties up to date in real time. This is why the View-Model is created with a function called "observable". The properties inside, being observable, report changes back up the chain so that the data-bound fields always reflect the latest data. Let's see some examples.

Adding data dynamically

Building on the example we just saw, add this horizontal rule and form just below the table in the HTML page:

<hr /> <form> <header>Add a Person</header> <input type="text" name="personName" placeholder="Name" data-bind="value: personName" /><br /> <input type="text" name="personHairColor" placeholder="Hair Color" data-bind="value: personHairColor" /><br /> <input type="text" name="personFavFood" placeholder="Favorite Food" data-bind="value: personFavFood" /><br /> <button type="button" data-bind="click: addPerson">Add</button> </form>

This adds a form to the page so that a user can enter data for a new person that should appear in the table. Note that we have added some data-bind attributes, but this time we are binding the value of the input fields not the text. Note also that we have added a data-bind attribute to the button at the bottom of the form that binds the click event of that button with a function inside our View-Model. By binding the click event to the addPerson JavaScript method, the addPerson method will be fired every time this button is clicked.

These bindings keep the value of those input fields linked with the View-Model object at all times. If the value in one of these input fields changes, such as when a user types something in the box, the View-Model object will immediately see that change and update its properties to match; it will also update any areas of the page that are bound to the value of that property so that they match the new data as well.

The binding for the button is special because it allows the View-Model object to attach its own event handler to the click event for this element. Binding an event handler to an event is nothing special by itself, but it is important to do it this way (through the data-bind attribute) so that the specific running View-Model instance inside of the page has attached one of its functions to this event so that the code inside the event handler has access to this specific View-Model's data properties and values. It also allows for a very specific context to be passed to the event that would be very hard to access otherwise.

Here is the code I added to the View-Model just below the people array. The first three properties that we have in this example are what make up the Model. They contain that data that is observed and bound to the rest of the page:

personName: "", // Model property personHairColor: "", // Model property personFavFood: "", // Model property addPerson: function () { this.get("people").push({ name: this.get("personName"), hairColor: this.get("personHairColor"), favoriteFood: this.get("personFavFood") }); this.set("personName", ""); this.set("personHairColor", ""); this.set("personFavFood", ""); }

The first several properties you see are the same properties that we are binding to in the input form above. They start with an empty value because the form should not have any values when the page is first loaded. It is still important to declare these empty properties inside the View-Model in order that their value can be tracked when it changes.

The function after the data properties, addPerson , is what we have bound to the click event of the button in the input form. Here in this function we are accessing the people array and adding a new record to it based on what the user has supplied in the form fields. Notice that we have to use the this.get() and this.set() functions to access the data inside of our View-Model. This is important because the properties in this View-Model are special observable properties so accessing their values directly may not give you the results you would expect.

The most significant thing that you should notice about the addPerson function is that it is interacting with the data on the page through the View-Model properties. It is not using jQuery, document.querySelector, or any other DOM interaction to read the value of the elements! Since we declared a data-bind attribute on the values of the input elements to the properties of our View-Model, we can always get the value from those elements by accessing the View-Model itself. The values are tracked at all times. This allows us to both retrieve and then change those View-Model properties inside the addPerson function and the HTML page will show the changes right as it happens. By calling this.set() on the properties and changing their values to an empty string, the HTML page will clear the values that the user just typed and added to the table. Once again, we change the View-Model properties without needing access to the HTML ourselves.

Here is the complete source of this example:

<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>MVVM Demo 2</title> <scriptsrc ="/Scripts/kendo/jquery.js"></script> <scriptsrc ="/Scripts/kendo/kendo.all.js"></script> <link href="/Content/kendo/kendo.common.css" rel="stylesheet" /> <link href="/Content/kendo/kendo.default.css" rel="stylesheet" /> <style type="text/css"> th { width: 135px; } </style> </head> <body> <table> <caption>People Data</caption> <thead> <tr> <th>Name</th> <th>Hair Color</th> <th>Favorite Food</th> </tr> </thead> <tbody data-template="row-template" data-bind="source: people"></tbody> </table> <hr /> <form> <header>Add a Person</header> <input type="text" name="personName" placeholder="Name"

data-bind="value: personName" /><br /> <input type="text" name="personHairColor" placeholder="Hair Color"

data-bind="value: personHairColor" /><br /> <input type="text" name="personFavFood" placeholder="Favorite Food"

data-bind="value: personFavFood" /><br /> <button type="button" data-bind="click: addPerson">Add</button> </form> <script id="row-template" type="text/x-kendo-template"> <tr> <td data-bind="text: name"></td> <td data-bind="text: hairColor"></td> <td data-bind="text: favoriteFood"></td> </tr> </script> <script type="text/javascript"> var viewModel = kendo.observable({ people: [ {name: "John", hairColor: "Blonde", favoriteFood: "Burger"}, {name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"}, {name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad"} ], personName: "", personHairColor: "", personFavFood: "", addPerson: function () { this.get("people").push({ name: this.get("personName"), hairColor: this.get("personHairColor"), favoriteFood: this.get("personFavFood") }); this.set("personName", ""); this.set("personHairColor", ""); this.set("personFavFood", ""); } }); kendo.bind($("body"), viewModel); </script> </body> </html>

And here is a screenshot of the page in action. You will see that one additional person has been added to the table by filling out the form. Try it out yourself to see the immediate interaction that you get with this code:

Using observable properties in the View

We just saw how simple it is to add new data to observable collections in the View-Model, and how this causes any data-bound elements to immediately show that new data. Let's add some more functionality to illustrate working with individual elements and see how their observable values can update content on the page.

To demonstrate this new functionality, I have added some columns to the table:

<table> <caption>People Data</caption> <thead> <tr> <th>Name</th> <th>Hair Color</th> <th>Favorite Food</th> <th></th> <th>Live Data</th> </tr> </thead> <tbody data-template="row-template" data-bind="source: people"></tbody> </table>

The first new column has no heading text but will contain a button on the page for each of the table rows. The second new column will be displaying the value of the "live data" in the View-Model for each of the objects displayed in the table.

Here is the updated row template:

<script id="row-template" type="text/x-kendo-template"> <tr> <td><input type="text" data-bind="value: name" /></td> <td><input type="text" data-bind="value: hairColor" /></td> <td><input type="text" data-bind="value: favoriteFood" /></td> <td><button type="button" data-bind="click: deletePerson">Delete</button></td> <td><span data-bind="text: name"></span>&nbsp;-&nbsp; <span data-bind="text: hairColor"></span>&nbsp;-&nbsp; <span data-bind="text: favoriteFood"></span></td> </tr> </script>

Notice that I have replaced all of the simple text data-bind attributes with input elements and valuedata-bind attributes. I also added a button with a clickdata-bind attribute and a column that displays the text of the three properties so that you can see the observable behavior in real time.

The View-Model gets a new method for the delete button:

deletePerson: function (e) { var person = e.data; var people = this.get("people"); var index = people.indexOf(person); people.splice(index, 1); }

When this function is called through the binding that Kendo UI has created, it passes an event argument, here called e, into the function that contains a data property. This data property is a reference to the model object that was used to render the specific row of data. In this function, I created a person variable for a reference to the person in this row and a reference to the people array; we then use the index of this person to splice it out of the array. When you click on the Delete button, you can observe the table reacting immediately to the change.

Here is the full source code of the updated View-Model:

<script id="row-template" type="text/x-kendo-template"> <tr> <td><input type="text" data-bind="value: name" /></td> <td><input type="text" data-bind="value: hairColor" /></td><td>

<input type="text" data-bind="value: favoriteFood" /></td> <td><button type="button" data-bind="click: deletePerson">Delete</button></td> <td><span data-bind="text: name"></span>&nbsp;-&nbsp; <span data-bind="text: hairColor"></span>&nbsp;-&nbsp; <span data-bind="text: favoriteFood"></span></td></tr> </script><script type="text/javascript"> var viewModel = kendo.observable({ people: [ {name: "John", hairColor: "Blonde", favoriteFood: "Burger"}, {name: "Bryan", hairColor: "Brown", favoriteFood: "Steak"}, {name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad"} ], personName: "", personHairColor: "", personFavFood: "", addPerson: function () { this.get("people").push({ name: this.get("personName"), hairColor: this.get("personHairColor"), favoriteFood: this.get("personFavFood") }); this.set("personName", ""); this.set("personHairColor", ""); this.set("personFavFood", ""); }, deletePerson: function (e) { var person = e.data; var people = this.get("people"); var index = people.indexOf(person); people.splice(index, 1); } }); kendo.bind($("body"), viewModel); </script> </body> </html>

Here is a screenshot of the new page:

Click on the Delete button to see an entry disappear. You can also see that I have added a new person to the table and that I have made changes in the input boxes of the table and that those changes immediately show up on the right-hand side. This indicates that the View-Model is keeping track of the live data and updating its bindings accordingly.

Learning Kendo UI Web Development An easy-to-follow practical tutorial to add exciting features to your web pages without being a JavaScript expert with this book and ebook
Published: May 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

Making better use of observable arrays

In the last several examples, we have been using an array called people to show a dynamic table with Kendo UI bindings. This has worked fine so far, but with more complicated Models and functionality we can run into a wall, so to speak. For example, there is no way to have the "live data" come from the Model objects themselves; we had to concatenate three span elements in the template to form the final output. This could cause problems for more complicated and full-featured pages, where you may have an array of Model objects that need to be able to handle events and calculate values on their own, instead of at the View-Model level.

Modify the row template like this:

<script id="row-template" type="text/x-kendo-template"> <tr> <td><input type="text" data-bind="value: name.stuff" /></td> <td><input type="text" data-bind="value: hairColor.stuff" /></td> <td><input type="text" data-bind="value: favoriteFood.stuff" /></td> <td><button type="button" data-bind="click: deletePerson">Delete</button></td> <td data-bind="text: dataString"></td> </tr> </script>

We have changed the property names in the data-bind declaration so that they point to an inner property that we created for them, called stuff. The important part of the example is that we also changed the final column to point to a calculated value function called dataString . The meaning of this will become clear as we continue. Next, update the JavaScript block for the View-Model so that it looks like this:

<script type="text/javascript"> var viewModel = kendo.observable({ people: [], personName: "", personHairColor: "", personFavFood: "", addPerson: function () { this.get("people").push(new person({ name: this.get("personName"), hairColor: this.get("personHairColor"), favoriteFood: this.get("personFavFood") })); this.set("personName", ""); this.set("personHairColor", ""); this.set("personFavFood", ""); }, deletePerson: function (e) { var person = e.data; var people = this.get("people"); var index = people.indexOf(person); people.splice(index, 1); } }); var person = function (data) { var self = this; this.name = kendo.observable({ stuff: data.name }); this.hairColor = kendo.observable({ stuff: data.hairColor }); this.favoriteFood = kendo.observable({ stuff: data.favoriteFood }); this.dataString = function () { returnself.name.get("stuff") + " - " + self.hairColor.get("stuff") + " - " + self.favoriteFood.get("stuff"); } }; viewModel.get("people").push(new person({ name: "John", hairColor: "Blonde", favoriteFood: "Burger" })); viewModel.get("people").push(new person({ name: "Bryan", hairColor: "Brown", favoriteFood: "Steak" })); viewModel.get("people").push(new person({ name: "Jennifer", hairColor:"Brown", favoriteFood: "Salad" })); kendo.bind($("body"), viewModel); </script>

We made several changes, so let's step through them carefully. The first important change is right at the top, where we have replaced the static array declaration with the people property as an empty array with the bracket notation []. Secondly, we created a new type of object called person and gave it a constructor function with its own internal observable objects. Each of these observable objects needs an object to manage, simple values don't work quite as well, so we made an arbitrary property for them called stuff. The only thing going on here is that the properties of this new person object type are pointing to observable objects instead of simple data. Why? Because if the properties are not observable, then the View-Model will not be notified of the change and the user interface will not be updated through data-binding.

The purpose of this change is to enable calculated values local to the specific instance of the object, which we have done with the dataString function inside of the person constructor. As you can see, the dataString function extracts the values from the locally observable properties and returns them as a formatted string. This is significant because it means that every person object has its own copy of this function, and that the View-Model itself is not involved in this calculation. This means that each object inside of the View-Model's people array can observe changes specific to itself and calculate values based on those changes. This type of Model can become very useful for advanced scenarios.

After declaring the person constructor function, we manually added some new person objects to the people array and then called kendo.bind() as usual. When rendered, the page looks and behaves just as it did in the previous example, but now the Model objects are smarter. Here is the full source code of the updated View-Model:

<script id="row-template" type="text/x-kendo-template"> <tr> <td><input type="text" data-bind="value: name.d" /></td> <td><input type="text" data-bind="value: hairColor.d" /></td> <td><input type="text" data-bind="value: favoriteFood.d" /></td> <td><button type="button" data-bind="click: deletePerson">Delete</button></td> <td data-bind="text: dataString"></td> </tr> </script> <script type="text/javascript"> var viewModel = kendo.observable({ people: [], personName: "", personHairColor: "", personFavFood: "", addPerson: function () { this.get("people").push(new person({ name: this.get("personName"), hairColor: this.get("personHairColor"), favoriteFood: this.get("personFavFood") })); this.set("personName", ""); this.set("personHairColor", ""); this.set("personFavFood", ""); }, deletePerson: function (e) { var person = e.data; var people = this.get("people"); var index = people.indexOf(person); people.splice(index, 1); } }); var person = function (data) { var self = this; this.name = kendo.observable({ d: data.name }); this.hairColor = kendo.observable({ d: data.hairColor }); this.favoriteFood = kendo.observable({ d: data.favoriteFood }); this.dataString = function () { returnself.name.get("d") + " - " + self.hairColor.get("d") + " - " + self.favoriteFood.get("d"); } }; viewModel.get("people").push(new person({ name: "John", hairColor: "Blonde", favoriteFood: "Burger" })); viewModel.get("people").push(new person({ name: "Bryan", hairColor: "Brown", favoriteFood: "Steak" })); viewModel.get("people").push(new person({ name: "Jennifer", hairColor: "Brown", favoriteFood: "Salad" })); kendo.bind($("body"), viewModel); </script> </body> </html>

And the output when the page is run:

Data-bind properties for Kendo MVVM

Data-bind properties for Kendo MVVM

There are thirteen different types of values that can be used inside of the data-bind Kendo UI attribute. Here is a summary of their definitions and uses.

The attr property

The attr property is used to bind the value of a View-Model to a specific HTML attribute of a page element. For example, this is very useful for setting attributes such as the src for an image or the href for an anchor tag.

... //View-Model definition imageSource: 'http://www.images.com/randomImage.jpg', ... <img data-bind="attr: {src: imageSource}" />

A binding like this would guarantee that the image would change along with the View-Model to allow for dynamically loading or changing images on a web page.

Note that the attr property can set multiple attributes at once when they are separated by commas like this:

data-bind="attr: {attribute1: value, attribute2: value, attribute3: value, ...}"

This property can be used with any HTML element and with any valid HTML attribute (including custom HTML5 data-* attributes).

The checked property

The checked property is used to bind the checked status of an input element with type checkbox or radio. For checkboxes, the data-bound property can be either a Boolean (true/false) value or an array. For radio selections, the property needs to be a string. For example:

isChecked: true, ... // Simple Boolean binding // The data-bound property will be updated when the user clicks the

checkbox <input type="checkbox" data-bind="checked: isChecked" /> animals: ["cow", "pig"], ... // Array binding for checkboxes // The array will change based on which checkboxes are checked by the

user // The initial page will show both the "cow" and "pig" inputs as

checked <input type="checkbox" value="horse" data-bind="checked: animals" /> <input type="checkbox" value="cow" data-bind="checked: animals" /> <input type="checkbox" value="pig" data-bind="checked: animals" /> tablet: "surface", ... // String binding for radio buttons // The string will change based on which radio option is selected by

the user // The initial page will show the input with the value "surface"

as checked <input type="radio" name="tablet" value="surface" data-bind="checked:

tablet" /> <input type="radio" name="tablet" value="ipad" data-bind="checked:

tablet" /> <input type="radio" name="tablet" value="android" data-bind="checked:

tablet" />

As you will see later, the checked binding can be very useful in conjunction with the visible/invisible bindings so that the checkboxes or radio buttons on the page will dynamically show or hide other portions of the page.

The click property

The click property binds the click event of a button to a function inside of the View-Model. It is a shortcut to the events binding that we will see later. Unlike a traditional click event wire-up, the Kendo UI framework will pass context data to the event handler to allow for a richer event-handling experience. For example, when a click event is bound within a row template, the event argument passed to the event handler will have access to the item from the source collection. This allows the event handler to operate against that Model data directly without any further DOM exploration and keeps all of the observable functionality in place.

Technically, Kendo UI supplies the DOM event wrapped in a jQuery event object to the event handler indicated in the binding, but it also manages the data property like we talked about in the previous paragraph. Since the event argument is still connected to the DOM event, you can call stopPropogation() and preventDefault() on that event argument to stop the DOM from performing any other actions in the page.

We already saw examples of the click binding in our code samples above so here are some of the snippets that we used there:

// Our example row template that included the click binding that will // pass the data property to the event handler <script id="row-template" type="text/x-kendo-template"> <tr> <td><input type="text" data-bind="value: name.d" /></td> <td><input type="text" data-bind="value: hairColor.d" /></td> <td><input type="text" data-bind="value: favoriteFood.d" /></td> <td><button type="button" data-bind="click: deletePerson">Delete</button></td> <td data-bind="text: dataString"></td> </tr> </script> // Our example form that included the click binding that has no // relevant data property to pass to the event handler <form> <header>Add a Person</header> <input type="text" name="personName" placeholder="Name" data-bind="value: personName" /><br /> <input type="text" name="personHairColor" placeholder="Hair Color" data-bind="value: personHairColor" /><br /> <input type="text" name="personFavFood" placeholder="Favorite Food" data-bind="value: personFavFood" /><br /> <button type="button" data-bind="click: addPerson">Add</button> </form> ... // This version of the click binding does not use the event argument addPerson: function () { this.get("people").push(new person({ name: this.get("personName"), hairColor: this.get("personHairColor"), favoriteFood: this.get("personFavFood") })); this.set("personName", ""); this.set("personHairColor", ""); this.set("personFavFood", ""); }, // This version of the click binding uses the event argument to // current data item from the source collection deletePerson: function (e) { var person = e.data; var people = this.get("people"); var index = people.indexOf(person); people.splice(index, 1); }

The custom property

Kendo UI allows for custom bindings so that you can create custom behaviors related to the View-Model of your page. An example on the Kendo UI documentation site uses a jQuery UI slideDown and slideUp call based on a Boolean value in the View-Model as a short-cut to some UI transformations. Refer to the Kendo UI documentation for a more detailed API reference for custom bindings.

The disabled/enabled properties

The disabled and enabled bindings work on input, select, and text area HTML elements. Just as their names would indicate, they disable or enable the bound elements respectively. These bindings are designed for use with Boolean properties, but for the sake of JavaScript loose-typing they will consider the non-Boolean values 0, null, undefined, and "" (empty string) as false and all other non-Boolean values as true. An example code is as follows:

allowEdit: false, ... // This input element will be initially disabled until the View-Model's

allowEdit // View-Model's allowEdit property is changed to true <input type="text" data-bind="enabled: allowEdit" />

The events property

The events binding is a convenient way to wire-up event handlers in your View-Model to events on HTML elements in your View. The click binding, as we saw above, is a specific example of this pattern and operates in exactly the same way. For example:

<button type="button" data-bind="events: {blur: blurHandler, click:

clickHandler, mouseover: mouseHandler,...}">Interactive Button</button>

The html/text properties

The html binding sets the innerHtml content of an HTML element using the value of a property from the View-Model. This binding differs from the text binding in that it does not encode HTML tags before generating its output, which means that HTML tags in the View-Model property will be rendered as HTML instead of as text (which is probably what you want if you are using the html binding). An example:

spanContent: "<strong>Some Content</strong>",... <span data-bind="html: spanContent"></span>

This would generate output like this in the source of the rendered page:

<span><strong>Some Content</strong></span>

The text binding works in exactly the same way as the html binding, except that it sets the simple text between element tags and it does encode HTML before output, so do not put HTML in the property containing the text to display unless you want the tags to show as part of the text output.

The invisible/visible properties

The invisible and visible bindings work on HTML elements that you want to either show or hide dynamically. Just as their names indicate, they make the given element invisible or visible respectively. These bindings are designed for use with Boolean properties, but for the sake of JavaScript loose-typing they will consider the non-Boolean values 0, null, undefined, and "" (empty string) as false and all other non-Boolean values as true. An example code is as follows:

showDetails: true, ... // This element will be initially visible unless the View-Model's // showDetails property is changed to false <pdata-bind="visible: showDetails">All sorts of text here...</p>

As mentioned earlier, it can be very useful to connect the value of a checkbox or a radio button with the visible status of other elements on a page. This allows you to change what data is displayed on the page based on selections that the user makes. Here is a simple example:

showDetails: false, ... <input type="checkbox" data-bind="checked: showDetails" name=

"showDetails" /> <p data-bind="visible: showDetails">All sorts of text and details…</p>

This code will make the checkbox control the visibility of the paragraph element that would contain some text that you only want displayed if the checkbox is checked. This is probably simpler than code you would use in a normal web application, but it illustrates the basic point.

The source property

The source binding is designed to render a Kendo UI template using the value of a View-Model property. If the property is an array, then the Kendo UI framework will render the template for each element of the array. This template is specified by the data-template attribute attached to the HTML element in question, and should indicate the template by its id attribute. When the templates are rendered, they will be placed directly beneath the element with the source attribute in the DOM. This is why you would place the source attribute on the tbody element of a table so that the tr elements in the Kendo UI template will be rendered and placed directly beneath it in the DOM so that they will appear as rows in a table. This binding can work on any element where it makes sense to include a collection of lower level elements, a table is just a natural example; other good uses would be ul, ol, and select elements.

We saw the source binding with a table already in our code samples. I will paste a little of it here as a reminder:

// table with the source binding on the tbody element <table> <caption>People Data</caption> <thead> <tr> <th>Name</th> <th>Hair Color</th> <th>Favorite Food</th> <th></th> <th>Live Data</th> </tr> </thead> <tbody data-template="row-template" data-bind="source: people"></tbody> </table> ... // the template that creates the rows <script id="row-template" type="text/x-kendo-template"> <tr> <td><input type="text" data-bind="value: name.d" /></td> <td><input type="text" data-bind="value: hairColor.d" /></td> <td><input type="text" data-bind="value: favoriteFood.d" /></td> <td><button type="button" data-bind="click: deletePerson">Delete</button></td> <td data-bind="text: dataString"></td> </tr> </script>

This is a good example of using the source binding with an array of objects. The source binding can also be used with an array of simple values, in which case you would use the keyword this inside the template instead of a property name inside an object:

<script id="row-template" type="text/x-kendo/template"> <tr> <td data-bind="text: this"></td> </tr> </script>

The source binding can also be used with a single object (as opposed to an array) in which case it behaves just like binding to an array with a single element. You can also bind to the View-Model itself if you want to access a single property within it as the source, in which case you reference the source as a property of the this keyword:

// table with the source binding on the tbody element <table>

<caption>People Data</caption> <thead> <tr> <th>Name</th>

<th>Hair Color</th>
<th>Favorite Food</th> <th></th>

<th>Live Data</th> </tr> </thead>

<tbody data-template="row-template" data-bind="source: viewModel">

</tbody> </table> ... // the template that creates the rows

<script id="row-template" type="text/x-kendo-template"> <tr>

<td><input type="text" data-bind="value: this.name" /></td>

<td><input type="text" data-bind="value: this.hairColor" />

</td> <td><input type="text" data-bind="value: this.favoriteFood" />

</td> <td>

<button type="button" data-bind="click: deletePerson">Delete</button>

</td> <td data-bind="text: dataString"></td> </tr> </script> ...

<script type="text/javascript> var viewModel = kendo.observable

({ name: "john", hairColor: "blonde", favoriteFood: "burger" }); ...

</script>

Notice how the structure is the same as if you were referencing a single object, but we are using the this keyword since we are referencing the View-Model directly.

When binding to a select element, note that you can use an array of simple values or an array of objects. If you just an array of objects, use the data-text-field to indicate which property contains the text to display within each option, and use the data-value-field to indicate which property contains the value within each option element.

The style property

The style binding is a great way to create a dynamic relationship between data in your View-Model and CSS styles on your page. It is a very simple binding that creates a direct relationship between the properties in your View-Model and the styles in your markup. An example:

<span data-bind="style: {color: myColor, fontWeight: myFontWeight}" /> <script type="text/javascript"> var viewModel = kendo.observable({ myColor: "orange", myFontWeight: "bold" }); </script>

Obviously, this becomes a lot more useful if you tie some logic to the styles you are using in your page, such as changing the styles for alternating table rows or changing the color of text if it meets some special criteria (such as an overdrawn balance looking red).

Notice that we used the style property fontWeight which should look strange to you. If you need to reference styles that normally contain a hyphen (font-weight), you need to use a camel-cased version in the binding so that it works as a valid JavaScript property name. So font-weight becomes fontWeight in the actual binding statement.

Finally, if you set the style value to an empty string, it will reset the value back to its original setting.

The value property

The value binding works in a very similar way to the text binding, except that it sets the value of an input element instead of the text of a display element. The bound value in the View-Model is updated on blur by default, such as when you press Tab to leave the input element on the page. If you want the View-Model property to be updated based on a different DOM event, you can set that in the data-value-update property on the same element as the binding. We have already seen the use of the value binding in our code samples. Here is an example of using the data-value-update binding to customize some behavior:

// the row template <script id="row-template" type="text/x-kendo-template"> <tr> <td><input type="text" data-bind="value: name" data-value-update="keyup" /></td> </tr> </script>

Remember that this is a two-way binding and is most useful for retrieving data from the users as they fill out a form.

Much like the checked binding that we saw above, the value binding works with select elements in a similar way. By binding the value of a select element to a string property, it will be bound to the value of the selected option element inside of the select element if the options have values, or the text of the selected option element if no value is present. Here is how this would look in the markup:

// Binding using the value, the selectedCar property will be bound to

the numbers <select data-bind="value: selectedCar"> <option value="1">Honda</option> <option value="2">Toyota</option> <option value="3">Ford</option> </select> // Binding using the text, the selectedCar property will be bound to

the text // between the option tags <select data-bind="value: selectedCar"> <option>Honda</option> <option>Toyota</option> <option>Ford</option> </select>

Of course, you can also bind both the source and the value of a select element to the View-Model. You are not limited to a single binding in the data-bind property. Also, as you might expect, you can bind the value of a multiple-select element if you are binding it to an array (instead of a simple string) so that it can hold multiple values.

Declarative widgets through Data-Role MVVM attributes

Declarative widgets through Data-Role MVVM attributes

Kendo's MVVM also allows declarative initialization of widgets through the data-role attribute. Declarative initialization is a different method of creating Kendo widgets by using the data-role attribute instead of setting up the widget through JavaScript. This is not as flexible as the JavaScript method, but it does allow for a lot of functionality with almost no code at all. Here is a section of code taken from the Kendo UI Web website that shows some basic set up as an introduction. The full details for these widgets can be found there.

<table> <tr> <th>Widget</th> </tr> <tr> <td> <h4>AutoComplete</h4> <input data-role="autocomplete" data-text-field="name" data-bind="source: colors, value: autoCompleteValue"/> </td> </tr> <tr> <td> <h4>ComboBox</h4> <select data-role="combobox" data-text-field="name" data-value-field="value" data-bind="source: colors, value: comboBoxValue"></select> </td> </tr> <tr> <td> <h4>DatePicker</h4> <input data-role="datepicker" data-bind="value: datePickerValue" /> </td> </tr> <tr> <td> <h4>DropDownList</h4> <select data-role="dropdownlist" data-text-field="name" data-value-field="value" data-bind="source: colors, value: dropDownListValue"></select> </td> </tr> <tr> <td> <h4>Grid</h4> <div data-role="grid" data-sortable="true" data-editable="true" data-columns='["Name", "Price", "UnitsInStock", {"command": "destroy"}]' data-bind="source: gridSource"></div> </td> </tr> <tr> <td> <h4>NumericTextBox</h4> <input data-role="numerictextbox" data-format="c" data-bind="value: numericTextBoxValue" /> </td> </tr> <tr> <td> <h4>Slider</h4> <input data-role="slider" data-bind="value: sliderValue" /> </td> </tr> <tr> <td> <h4>TimePicker</h4> <input data-role="timepicker" data-bind="value: timePickerValue" /> </td> </tr> <tr> <td> <h4>TabStrip</h4> <div data-role="tabstrip" data-animation="false"> <ul> <li class="k-state-active">First</li> <li>Second</li> </ul> <div> <h4>First page:</h4> Pick a time: <input data-role="timepicker" data-bind="value: timePickerValue"/> </div> <div> <h4>Second page:</h4> Time is: <span data-bind="text: displayTimePickerValue"></span> </div> </div> </td> </tr> <tr> <td> <h4>TreeView</h4> <div data-role="treeview" data-animation="false" data-drag-and-drop="true" data-bind="source: treeviewSource"></div> </td> </tr> </table>

This is a great example of using multiple bindings together, and of which bindings rightly pertain to which widgets.

Summary

Summary

The Kendo MVVM framework brings complicated interactive JavaScript into the realm of simple HTML attributes, templates, and View-Model functions. It is a very powerful feature and is one that you are likely to become very accustomed to using in your web pages. Keep in mind as you develop code that Kendo is a system in which features can be built together very nicely; for example, you could use a Kendo data source object as the source binding for a table or select list.

When you have powerful tools like this within your reach, you will find that function-rich pages become normal instead of exceptionally difficult and that your programming experience will be better than ever.

Resources for Article :


Further resources on this subject:


Learning Kendo UI Web Development An easy-to-follow practical tutorial to add exciting features to your web pages without being a JavaScript expert with this book and ebook
Published: May 2013
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


John Adams

John Adams currently works as an application development consultant in the Dallas/Fort Worth area for a fantastic company called RBA. He has been developing custom business applications with the Microsoft .NET platform for 6 years and has specialized in development with ASP.NET MVC. He loves writing code and creating solutions. Above all, he loves his wife and children and the lord Jesus Christ.

Books From Packt


Instant Kendo UI Mobile
Instant Kendo UI Mobile

Instant Kendo UI Grid
Instant Kendo UI Grid

jQuery Mobile Web Development Essentials
jQuery Mobile Web Development Essentials

jQuery Mobile Web Development Essentials, Second Edition
jQuery Mobile Web Development Essentials, Second Edition

Learning jQuery, Third Edition
Learning jQuery, Third Edition

WordPress Mobile Web Development: Beginner's Guide
WordPress Mobile Web Development: Beginner's Guide

jQuery Tools UI Library
jQuery Tools UI Library

Learning jQuery - Fourth Edition
Learning jQuery - Fourth Edition


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
G
f
N
m
t
g
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software