PhoneGap, Kendo, and MVVM by Example

I’ve been looking into developing PhoneGap applications. PhoneGap is an excellent tool for getting an application into the app store for iOS, Android, Windows 8/Phone 8, and many other platforms. Since it’s HTML 5 and JavaScript-Based, running on the web browser of the target platform, PhoneGap requires only a single codebase (however, there can be some quirks with the various features, as described in the PhoneGap documentation). Since it’s HTML; you can virtually have whatever design you would like.

However, to go with a minimalist design would not be very user friendly. It’s often best to use a framework like JQuery Mobile, Sensa Touch, or others to handle the look and feel for you. These frameworks provide you with a header and footer similar to apps you would see in the application store, and provide enhanced UI input and layout elements. This is why I chose a framework to lay out the markup for me, and this is also why I chose to use Kendo UI, from Telerik. Kendo UI provides a mobile application framework that supplies a templated UI to the user that completely resembles a mobile application. It also provides a series of input widgets perfect for capturing user input that’s much more appealing ot the user than the standard HTML controlset. It also provides an MVVM framework, and a Single Page Application framework for managing your application’s interaction between the view and model. Note that Kendo comes in three different frameworks: kendo UI web for web controls, Kendo UI Mobile for mobile web applications and PhoneGap, and Kendo UI DataViz, or data visualization components (charting, etc.).

The sample application is the shell we are going to plant into a phonegap application (discussed in a later post). To start, we are going to build is an application containing two views, using data that’s bound to the view via the MVVM framework. In all of my searching on the internet, I had trouble finding a simple example incorporating these exact features, so I hope the following example is a benefit to you. I’ll also describe the Kendo UI framework as I go. To begin, we need to create an HTML page and add some core script definitions to it.

<link href="../../css/kendo.common.min.css" rel="stylesheet" />
<link href="../../css/kendo.bootstrap.min.css" rel="stylesheet" />
<link href="../../css/kendo.mobile.all.min.css" rel="stylesheet" />

<script src="../../js/jquery.js"></script>
<script src="../../js/jquery.migrate.min.js"></script>
<script src="../../js/kendo.all.min.js"></script>

I’ve included the Common, Bootstrap (as in bootstrap theme, not Twitter Bootstrap), and the mobile CSS files. All of these provided allows you to use the Kendo UI web and mobile controls. Additionally, I’ve included JQuery (a requirement of Kendo), which is the latest. The migrate JS file is an add-on that ensures backward compatibility between older versions of JQuery (as of the time of writing, this example used JQuery 1.9.1, but Kendo requires 1.8.2). Additionally, the kendo all JS file contains all of the scripts for the web, mobile, and dataviz frameworks.

Now that we have our references setup, let’s flesh out the UI. To begin, let’s setup the views and the layout, as the following:

<div id="newview" data-role="view" data-title="New Contact" 
  data-layout="viewlayout" data-model="newViewModel">
	.
	.
</div>

<div id="existingview" data-role="view" data-title="Existing Contacts" 
  data-layout="viewlayout" data-model="existingViewModel">
	.
	.
</div>

<div data-role="layout" data-id="viewlayout">
	<header data-role="header">
		<div data-role="navbar">
			<a class="nav-button" data-align="left" data-role="backbutton">Back</a>
			<span data-role="view-title"></span>
		</div>
	</header>

	<footer data-role="footer">

		<div id="footertabs" data-role="tabstrip">
			<a href="#newview" data-icon="add">New</a>
			<a href="#existingview" data-icon="contacts">Contacts</a>
		</div>

	</footer>
</div>

To begin, we have two views, a new view and an existing view. A view is the container for what the user sees, defined by a data-role value of “view”; the user only sees one view at a time, starting with the new view. A view has a header and footer. The header contains the header title bar, plus any buttons used for navigation. The footer bar contains additional footer options, which is a set of tabs to navigate between the two views. Notice that the header and footer are defined an element with a data-role attribute value of “layout”. Layouts are a convenient way to reuse the header and footer across all views. This layout above is used for the new and existing view. Now we have the views defined, and the navigation between views using the tabstrip component. But if you viewed this page in the browser, it wouldn’t be very useful. For instance, the tabscript would not work as it currently stands. We need to enable a JavaScript widget that Kendo uses to provide the tabbing feature. Kendo uses a JQuery UI widget-like capability for enabling these behaviors. For instance, to enable the tabstrip programmatically, one would do:

$("#footertabs").kendoMobileTabStrip({ /* options */ });

However, Kendo made this even easier through it’s application class; by adding the following line, the entire view is wired up to it’s related JavaScript widget, all linked together through the data-role attribute, and related “data-” configurations.

var kendoApp = new kendo.mobile.Application(document.body, {
	loading: "Loading..."
});

Now that our views are wired up and our components are linked to their JavaScript counterpart, the next task needing performed is to define the MVVM data models. Before we fully get into that, let’s look again at the complete view.

<div id="newview" data-role="view" data-title="New Contact" data-layout="viewlayout" data-model="newViewModel">
	<form action="" method="post">
		<ul id="newformlist" data-role="listview">
			<li>
				<label>Name:</label>
				<input type="text" id="Name" data-bind="value:newName" />
			</li>
			<li>
				<label>Suffix:</label>
				<input type="text" id="Suffix" name="Suffix" data-bind="value:newSuffix" />
			</li>
			<li>
				<label>Email:</label>
				<input type="email" id="Email" name="Email" data-bind="value:newEmail" />
			</li>
			<li>
				<label>Phone:</label>
				<input type="tel" id="Phone" name="Phone" data-bind="value:newPhone" />
			</li>
		</ul>
	</form>
</div>

<div id="existingview" data-role="view" data-title="Existing Contacts" data-layout="viewlayout" data-model="existingViewModel">
	<ul id="existinglist" data-role="listview" data-bind="source:contacts" data-template="contacttemplate">
	</ul>
</div>

Here we ahve our two views. The first container a form, and the last contains a list. Both use the listview component, a mobile-specific component that binds data similar to a grid, or can be used as shown above for representing a form. Both views define certain attributes; they define a title that will appear in the layout’s title bar. The views also define the layout to use (as we saw above) and the data model to bind to. Within eaach view is an HTML element that defines what to bind to. For instance, in our form, each textbox is bound, using the data-bind attribute, to some specified value (newName, newEmail, etc). The “value:” prefix specifies the type of bindings to use. There are quite a few bindings available; for know, now that the value binding links the value from the view model to the “value” attribute of the element. In future posts, I’ll talk about some of the other attributes available. These bindings link the model (newViewModel) to an attribute of that model. This makes it very easy to bind the data in a two-way fashion from some backend model to the user interface, and vice versa.

Our listview that displays a list of contacts defines a source, or the array of data to bind to, and specifies a template to use. Templates are script element defining the UI to define for the item of the list. The following is the attached template the listview uses to show the name, phone, and email for each contact. Note that templates use a #= # or #: # convention for binding, and can even accept javascript statements like the “if” statement below.

<script type="text/x-kendo-template" id="contacttemplate">
	<h3>
		#= Name#
		# if (Suffix != null && Suffix.length > 0) { #
			#= Suffix #
		# } #
	</h3>
	<div>
		#= Phone #
	</div>
	<div>
		#= Email #
	</div>
</script>

To wire up these views, we need some data. This is where the view models come into play. Kendo defines a view model using the observable method; note that this approach is different than what other MVVM frameworks use (like Knockout JS for one). Kendo transforms the basic model definition into an object with observable properties to provide the two-way binding.

var newViewModel = kendo.observable({
	newName: "ABC",
	
	newSuffix: "",
	
	newPhone: "",
	
	newEmail: ""
});

var existingViewModel = kendo.observable({
	contactsLoaded: true,
	
	contacts: [
		{ Name: "Ted Person", Suffix: "", Email: "ted.person@fake.com", Phone: "555-555-5555" },
		{ Name: "Amu Person", Suffix: null, Email: "amy.person@fake.com", Phone: "555-555-5555" },
		{ Name: "Bob Person", Suffix: "Jr", Email: "bob.person@fake.com", Phone: "555-555-5555" }
	]
});

And voila, this is all that you need to define multiple views, binding them to an MVVM model. I’ve created a JS fiddle with the scripts; it’s not fully working correctly, which is something I have to contact Telerik about. But you can get the contents and scripts here (which work great locally), or the full example here.

6 thoughts on “PhoneGap, Kendo, and MVVM by Example

    • Yes, this post is PhoneGap light. The project I put together is hosted in PhoneGap, and I have it running on my android tablet. I plan to make this an upcoming post, and I should have stated that.

      Like

  1. Well, agree that phonegap doesn’t play too much here. Developers should be careful in choosing words as people tend to confuse what really phonegap does, they blame phonegap for non related things because of confusing articles or not well documented folks. Non personal, speaking from what I found in the web

    Like

Leave a comment