Monday, January 30, 2012

From a List to a Details View using jQueryMobile and Backbone.js

In my previous post I built a basic application to demonstrate the use of Backbone.js with jQueryMobile (JQM). The introduction can be found here, with a brief subsequent post on sorting collections here. In this post, I would like to add the capability to view the details of the items presented in the list view.

The first step is to create a new JQM page to display the details view. JQM makes it pretty easy to add pages to your application. I added the following code to the index.html file:

This will create the structure for the page, and Backbone.js will be used to fill in the content div based on the record tapped (or clicked) within the list view. The next step is to define the template for the details view. This is the pattern that I follow when developing using jQueryMobile and Backbone.js. The template can be inserted below the list item template in index.html.

I decided to embed the details in a read-only list view, this way jQueryMobile will provide some reasonable styling. Since the point here is to demonstrate Backbone and jQueryMobile playing together, I didn't want to have to spend much time on style :)

Next, we need to define the Backbone view that will use the template to render the appropriate content. All this View needs to do is apply the model to the template and append it to the HTML container defined when the View is instantiated.

In order to retrieve the correct model to bind to the details view, we need to know what row in the list view was clicked (or tapped). To do this, we can bind to the click event of the item in the list view. This can be accomplished by modifying the ActivityListView render method. Here is the current version of the list view:

The key area to focus on here is lines 18-20, where the activity item HTML is rendered and appended to the list view. This is where the modification needs to occur. Each activity item HTML element needs to be bound to a click event. In this click event, the activity id will need to somehow be passed to the details view so the appropriate look up can occur. There are several ways to do this. Approaches I have used in the past include the use of jQuery.jqmData(...) or session local storage (assuming HTML5). In this example, we will use the jqmData method. The trick is to capture the id during the rendering of the list so that it can be used during the execution of the click event. Below are the required modifications to lines 18-20 of the previous code snippet.

The first thing is to capture the rendered activity item HTML in a variable and cast it to a jQuery object, as can be seen in lines 2-3. Line 4 is where the activity id data is attached to our activity item HTML element. Then, the bind event (lines 5-8) retrieves the attached data and sets it on the activity details HTML element, which is our activity details page HTML. Per the jQuery documentation, this within a bind method refers to the DOM element to which the event handler is bound. We can use that to get at the activity id data and attach it to the details view. This gives us the ability to pass the appropriate id at runtime to the details page.

Now we need to wire all this together. The typical pattern I follow is to use the jQueryMobile pagebeforeshow event to set up everything needed to render a complete page. This acts as my controller.

This code retrieves the id data attached to the activity details element, looks up the model using the Backbone API (line 5), instantiates the view with the model and the view container, and calls the render method to render the final HTML. The end result looks like this:

The source code for this post can be found here. Note that this is a branch of my repository for this sample app. Each blog post associated with this code base resides on a separate branch.

Related Posts:

Tuesday, January 24, 2012

Spring 3.1 - Constructor Namespace

Spring Namespaces


Spring provides several namespaces to simplify XML configuration, such as jdbc, tx, aop, etc. We Spring developers are already familiar with the required beans namespace.

<beans>
  <bean id="dataSource" class="..."/>
  <bean id="messagingProvider" class="..."/>
</beans>

Spring Namespaces are defined at the top of the XML file. Here we define the namespaces we need to use, and reference the schema (XSD) that validates the XML.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.chariotsolutions"/>

    <bean id="simpleBean"
      class="com.chariotsolutions.springthreeone.SimpleBean"/>

</beans>

In Spring XML configuration we declare dependency injection with either "setter injection" (via properties tag) or "constructor injection". Spring already provided the Property or "p" namespace, to simplify property setting, in other words, invoking setters on a bean.

Here we have a simple bean that can be configured with either a constructor or setter.

public class SimpleBean {
  private String myString;
  private String myOtherString;

  public SimpleBean() {}

  public SimpleBean(String myString) {
    this.myString = myString;
  }

  public SimpleBean(String myString, String other) {
    this.myString = myString;
    this.myOtherString = other;
  }

  public String getMyString() {
    return myString;
  }

  public String getMyOtherString() {
    return myOtherString;
  }
}


Instead of

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="setterBean"
      class="com.chariotsolutions.springthreeone.SimpleBean">
        <property name="myString" value="Setter Set"/>
    </bean>

</beans>

We could use

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="setterBean"
    class="com.chariotsolutions.springthreeone.SimpleBean"
      p:myString="Setter Set"/>

</beans>

With the Property namespace, there is no significant benefit, it is simple a matter of preference.


Spring Constructor Injection

Some developers choose to use "constructor injection" for several reasons.
  • Setting required elements
  • Immutable classes for thread safety
  • Third party class that only provides constructor setting

One of the main issues with "constructor injection", prior to Spring 3.1, is that it is unclear which arguments are being set in the constructor injection. Also, if the constructor has multiple arguments, one can inadvertently set arguments in the wrong sequence.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="setterBean" class="com.chariotsolutions.springthreeone.SimpleBean">
    <constructor-arg value="squibbity doo"/>
    <constructor-arg value="flabbity doo"/>
  </bean>
</beans>

Spring 3.1 Constructor "c" Namespace

Unlike the "p" namespace, the "c" namespace provides us with descriptive references, allowing us to reference the constructor's arguments by name. This feature is even more useful when we have multiple constructor arguments, as below.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:c="http://www.springframework.org/schema/c"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="setterBean" class="com.chariotsolutions.springthreeone.SimpleBean"
    c:myString="squibbity doo"
    c:myOtherString="flabbity doo"/>

</beans>

Deployment Requirements

NOTE: Code using the "c" namespace, MUST be deployed with Java Debugging Tables (the -g option)!


Summary

We Spring developers have shortcuts at our disposal to make configuration easier or less terse. The new "c" namespace provides us the benefit of named variables that we know from using the "p" namespace or <property ... />. We should strive to make our beans immutable for thread safety. By using the "c" namespace get the developers lean towards property setting for readability.

Notice that both the "p" ad "c" namespaces do not have a schema reference in the XML header.

Monday, January 23, 2012

Introduction to Sencha Touch

Steve Smith recently looked at jQuery Mobile and Backbone using a simple application that allowed a user to track their daily exercise. I'm going to duplicate his example using Sencha Touch.

Sencha Touch is a framework for building mobile applications using HTML5, CSS3, and Javascript.  This example uses the Developer Preview of Sencha Touch 2.0.

Here's what our project looks like.

A Sencha Touch application is loaded from an HTML page. The HTML loads CSS and Javascript. Sencha Touch applications typically build the UI using Javascript so the index.html is very simple.

The touch/ directory contains the Sencha Javascript and CSS from the SDK.  Since this is an example, all if the application code is in one file, app.js. Larger applications will break the code up into more files and directories.

Sencha Application

Sencha Touch has a global namespace, Ext, that holds the framework and application code. The Ext.application helper function takes a configuration object where we define our application.

Ext.application({
    launch: function() {
        // define our app here
    }
});

Model

We extend Ext.data.Model to define a Model object describing our data. The data is supplied by the server in a JSON file, exercise.json. The fields in the model, match the properties in the JSON file.

Ext.define("Activity", {
    extend: "Ext.data.Model",
    fields: [
        {name: 'id', type: 'int'},
        {name: 'date', type: 'date'},    
        {name: 'type', type: 'string'},    
        {name: 'distance', type: 'string'},    
        {name: 'minutes', type: 'int'},  
        {name: 'comments', type: 'string'}
    ]
});
/* exercise.json */
[
    {
        "id":3,
        "date": "12/10/2011",
        "type": "Walk",
        "distance": "2.5 miles",
        "comments": "Shouldn't have taken the dog",
        "minutes": 45
    },
    ...
]  

Store

A Store is used to load and manage data. The Activity model we created is associated with the store. We define a proxy to load the JSON data from a URL. Finally, we tell the store to automatically load the data when the store is created.

var store = Ext.create('Ext.data.Store', {
    storeId: "activityStore",
    model: "Activity",
    proxy: {
        type: 'ajax',
        url: 'exercise.json'
    },
    autoLoad: true
});

Once the store is created, we can use the Javascript console to interact with the data.

User Interface

Now we need to display the data. A NavigationView shows a navigation bar and holds the List component. The list is defined in the code using the object literal syntax. The data store we created is assigned to the list so it can display the records. The itemTmp property defines how to display each item of data. This can be a template or a string.

var view = Ext.create("Ext.NavigationView", {
    fullscreen: true,
    items: [
        {
            xtype: 'list',
            title: 'Activities',
            itemTpl: '{date} - {type}',
            store: store
        }
    ]
});
Unformatted Date

This works but the date doesn't display very well. A format can be added to the template definition. {date} in the itemTpl becomes {date:date("m/d/Y")}.

var view = Ext.create("Ext.NavigationView", {
    fullscreen: true,
    items: [
        {
            xtype: 'list',
            title: 'Activities',
            itemTpl: '{date:date("m/d/Y")} - {type}',
            store: store
        }
    ]
});
Formatted Date

Adding New Data

Let's add a button to the header to add a new row of data.

view.getNavigationBar().add({
    xtype: 'button',
    text: 'Add',
    align: 'right',
    handler: addNewRow
});

The handler property of the button defines the function that is called whenever the button is pressed. Eventually we need a form so the user can add new data. For now, let's define a function addNewRow that will create a new row and add it to the store.

var addNewRow = function() {
    // future versions should display a form for adding a record
    var fakeRecord = Ext.create('Activity', {
        date: new Date(), 
        type: 'Walk', 
        distance: '2 miles', 
        minutes: 28, 
        comments: 'Auto generated record.'
    });

    store.add(fakeRecord);
};

Now when the button is pressed a new row appears in the UI.  The store notifies the list, so rows appear as records are added to the store.

Add Button

New Row

That should be enough to get you started. In future posts we'll look at features like sorting, detail views, navigation, and forms. The source code is available on github.

Tuesday, January 17, 2012

Spring 3.1 - Environment Profiles

Spring 3.1 Environment Profiles

Profiles

Spring 3.1 now includes support for the long awaited environment aware feature called profiles. Now we can activate profiles in our application, which allows us to define beans by deployment regions, such as "dev", "qa", "production", "cloud", etc.

We also can use this feature for other purposes: defining profiles for performance testing scenarios such as "cached" or "lazyload".

Essential Tokens

Spring profiles are enabled using the case insensitive tokens spring.profiles.active or spring_profiles_active.

This token can be set as:
  • an Environment Variable
  • a JVM Property
  • Web Parameter
  • Programmatic
Spring also looks for the token, spring.profiles.default, which can be used to set the default profile(s) if none are specified with spring.profiles.active.

Grouping Beans by Profile

Spring 3.1 provides nested bean definitions, providing the ability to define beans for various environments:
<beans profiles="dev,qa">
  <bean id="dataSource" class="..."/>
  <bean id="messagingProvider" class="..."/>
</beans>
Nested <beans> must appear last in the file.
Beans that are used in all profiles are declared in the outer <beans> as we always have, such as Service classes.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="businessService"
       class="com.c...s.springthreeone.business.SimpleBusinessServiceImpl"/>

    <beans profile="dev,qa">
        <bean id="constructorBean"
          class="com.chariotsolutions.springthreeone.SimpleBean"
              c:myString="Constructor Set"/>

        <bean id="setterBean"
          class="com.chariotsolutions.springthreeone.SimpleBean">
            <property name="myString" value="Setter Set"/>
        </bean>
    </beans>

    <beans profile="prod">
        <bean id="setterBean"
          class="com.chariotsolutions.springthreeone.SimpleBean">
            <property name="myString" value="Setter Set - in Production YO!"/>
        </bean>
    </beans>
</beans>

If we put a single <bean> declaration at below any nested <beans> tags we will get the exception org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'bean'.

Multiple beans can now share the same XML "id"
In a typical scenario, we would want the DataSource bean to be called dataSource in both all profiles. Spring now allow us to create multiple beans within an XML file with the same ID providing they are defined in different <beans> sets. In other words, ID uniqueness is only enforced within each <beans> set.

Automatic Profile Discovery (Programmatic)

We can configure a class to set our profile(s) during application startup by implementing the appropriate interface. For example, we may configure an application to set different profiles based on where the application is deployed - in CloudFoundry or running as a local web application. In the web.xml file we can include an Servlet context parameter, contextInitializerClasses, to bootstrap this class:
<context-param>
  <param-name>contextInitializerClasses</param-name>
  <param-value>com.chariotsolutions.springthreeone.services.CloudApplicationContextInitializer</param-value>
</context-param>

The Initializer class
package com.chariotsolutions.springthreeone.services;

import org.cloudfoundry.runtime.env.CloudEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;

public class CloudApplicationContextInitializer implements
  ApplicationContextInitializer<ConfigurableApplicationContext> {
    
  private static final Logger logger = LoggerFactory
    .getLogger(CloudApplicationContextInitializer.class);

  @Override
  public void initialize(ConfigurableApplicationContext applicationContext) {
    CloudEnvironment env = new CloudEnvironment();
    if (env.getInstanceInfo() != null) {
      logger.info("Application running in cloud. API '{}'",
        env.getCloudApiUri());
      applicationContext.getEnvironment().setActiveProfiles("cloud");
      applicationContext.refresh();
    } else {
      logger.info("Application running local");
      applicationContext.getEnvironment().setActiveProfiles("dev");
    }
  }
}

Annotation Support for JavaConfig

If we are are using JavaConfig to define our beans, Spring 3.1 includes the @Profile annotation for enabling bean config files by profile(s).

package com.chariotsolutions.springthreeone.configuration;

import com.chariotsolutions.springthreeone.SimpleBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev")
public class AppConfig {
  @Bean
  public SimpleBean simpleBean() {
    SimpleBean simpleBean = new SimpleBean();
    simpleBean.setMyString("Ripped Pants");
    return simpleBean;
  }
}

Testing with XML Configuration

With XML configuration we can simply add the annotation @ActiveProfiles to the JUnit test class. To include multiple profiles, use the format @ActiveProfiles(profiles = {"dev", "prod"})
package com.chariotsolutions.springthreeone;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@ActiveProfiles(profiles = "dev")
public class DevBeansTest {

  @Autowired
  ApplicationContext applicationContext;

  @Test
  public void testDevBeans() {
    SimpleBean simpleBean = 
      applicationContext.getBean("constructorBean", SimpleBean.class);
    assertNotNull(simpleBean);
  }

  @Test(expected = NoSuchBeanDefinitionException.class)
  public void testProdBean() {
    SimpleBean prodBean = applicationContext.getBean("prodBean", SimpleBean.class);
    assertNull(prodBean);
  }
}

Testing with JavaConfig

JavaConfig allows us to configure Spring with or without XML configuration. If we want to test beans that are defined in a Configuration class we configure our test with the loader and classes arguments of the @ContextConfiguration annotation.

package com.chariotsolutions.springthreeone.configuration;

import com.chariotsolutions.springthreeone.SimpleBean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)
@ActiveProfiles(profiles = "dev")
public class BeanConfigTest {

  @Autowired
  SimpleBean simpleBean;

  @Test
  public void testBeanAvailablity() {
    assertNotNull(simpleBean);
  }
}

Declarative Configuration in WEB.XML

If we desire to set the configuration in WEB.XML, this can be done with parameters on ContextLoaderListener.

Application Context
<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
<context-param>
  <param-name>spring.profiles.active</param-name>
  <param-value>DOUBLEUPMINT</param-value>
</context-param>
Log Results

DEBUG PropertySourcesPropertyResolver - Found key 'spring.profiles.active' in [servletContextInitParams] with type [String] and value 'DOUBLEUPMINT'


Environment Variable/JVM Parameter
Setting an environment variable can be done with either spring_profiles_default or spring_profiles_active. In Unix/Mac it would be export SPRING_PROFILES_DEFAULT=DEVELOPMENT for my local system.

We can also use the JVM "-D" parameter which also works with Maven when using Tomcat or Jetty plugins.

Note: Remember the tokens are NOT case sensitive and can use periods or underscores as separators. For Unix systems, you need to use the underscore, as above.

Logging of system level properties DEBUG PropertySourcesPropertyResolver - Found key 'spring.profiles.default' in [systemProperties] with type [String] and value 'dev,default'

Summary

Now we are equipped to activate various Spring bean sets, based on profiles we define. We can use  traditional, XML based configuration, or the features added to support JavaConfig originally introduced in Spring 3.0.

Thursday, January 12, 2012

Philly ETE - Speaker Interview, Ken Rimple co-author of Spring Roo in Action

For our first look at what’s in store for ETE 2012, we talk with our own Ken Rimple, co-author of Spring Roo in Action. Ken is Director of Education Services and is a regular co-host of Chariot’s TechCast – our monthly podcast series focusing on development and training in Spring, Rails, Scala, Hibernate, Maven and other emerging technologies in the field

Q: After last year’s tremendous following and turnout for ETE, people are really expecting this year to raise the bar. Tell us a bit about what you’ll be discussing at this year’s ETE and what people can expect from your presentation in particular.

Ken: I’ll be talking about the subject I actually wrote a book around – Spring Roo. It’s a software tool that helps people develop applications in Spring, which is a very popular Java application development platform. I’m going to talk about building Roo add-ons, which is kind of extending the features of the platform with ones that don’t exist today.

Q: So it’s all about building new features from scratch?

Ken: Exactly! For example, there are add-ons that configure different web frameworks, like Vaadin and JSF. At one point, there was an add-on for programming Flex applications [ed. note: this is currently non-functional], which are Flash-based frontends, and add-ons for other integrations to other systems.
I wrote two for the book: One to install JQuery, which is a Javascript framework, and another one that installs CoffeeScript, which is a language simplifying JavaScript. So, in my talk I’m going to go through how to write add-ons, because it’s such a new community. And I really want to boost the community’s presence so that people can start contributing to the framework.

Monday, January 9, 2012

Sorting collections with Backbone.js and jQuery Mobile

In a previous post, I provided a simple example of rendering an HTML list view using Backbone.js and jQuery Mobile. The code from that example ended up rendering a list like this:

Notice that the list is presented in the order that came from the JSON.

Also, when items are added to the list, they show up at the bottom. While easy, this isn't the best. In this post, I'll add sorting to the backbone collection and make a small change to the view so that as new items are added, the list is automatically sorted.

Backbone.js makes these changes very easy. In order for a Backbone collection to be sorted, you implement a comparator method on the collection. As models are added to the collection, Backbone will make sure the sorting is maintained based on the comparator implementation. From the Backbone documentation "Comparator functions take a model and return a numeric or string value by which the model should be ordered relative to others".

We will sort our list based on the date the exercise activity occurred. Since comparators must return a number or string for sorting, we will return the time in milliseconds since 1/1/70. Our new collection definition looks like this: If we refresh our browser with the updated collection implementation, notice that the list is now sorted by date.

If we wanted it sorted descending, we would simply return the negative value of the getTime() method.

If you tried to add a new activity, you'll notice that it shows up at the end of the list. This is due to the fact that we bind a listener to the add method of the collection (line 7 below), and all this does is append the HTML to the end of the list view (line 30 below).

If you were to open a JS console in the browser and investigate the collection by entering

JSON.stringify(exercise.activities)
you would see that the collection is ordered. To fix the HTML representation of the collection all we need to do is replace the add event binding to call render. This will re-render the HTML based on the collection. We can also remove the add method in the View, as it is no longer needed. Our updated View configuration looks like this:

After refreshing the view, the list will continue to be sorted even when adding new activities. Since the code just adds an item with todays date, try typing the following in the JS console

exercise.activities.add({id:12, date:"12/01/2011", type:"Interval Run"});

This should add an item at the top of the list. Now your exercise activity will always be sorted.

The source code can be found in my git repository here. This URL will take you to the "sort" branch. The master branch represents the code from the introduction blog post found here

Related Posts:

Tuesday, January 3, 2012

Introduction to Backbone.js with jQuery Mobile

If you are working on a JavaScript heavy application (think jQuery Mobile, etc.), you probably will want to look at some JavaScript libraries to help add structure, consistency and convenience to your applications. One of the JavaScript libraries I've used lately is Backbone.js. To quote Backbone themselves, it provides "models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.". This is really a great summary of what Backbone can provide to your application.

As an example of how to apply Backbone, I'll create a small jQuery Mobile app and use a Backbone model, collection and view to render the user interface. Through the use of Backbone's event model, the user interface will update as the model changes or new models are created.

I decided to use jQuery Mobile as the UI framework mainly because I am a mobile guy and it will provide the HTML with some reasonable style with no additional effort on my part. I know, lazy...but it works for this blog post :) Continuing on the lazy path, I will refer to jQuery Mobile as JQM from this point forward.

The following assumes you are at least a little familiar with jQuery and JQM. If not, take a look at the JQM website (http://jquerymobile.com/). They have some great documentation and even a template for creating a basic app. All of the code in this post will be available in my github repository (https://github.com/stevenpsmith/Exercise/tree/BackboneIntro).

The application we are going to make will allow a user to log exercise they have done on any given day. Please remember this is a very basic app for the sole purpose of demonstrating Backbone.js. The piece that will be developed for this post will involve pulling exercise data from a server and presenting it in a list view, a very common paradigm for mobile apps. In the end, our app will look like this:

The JSON we will be dealing with will look like this:

I like to organize my application structure a little differently than the JQM introduction shows, mainly for organizational reasons. My application structure looks like this:

All of our work will be done in index.html and app.js. In real applications I usually break down my JS files even further, but it really isn't necessary here. The list page of the application is defined within index.html. It should look like a typical JQM page definition with the only the content portion defined. We will use the Backbone View to create the list view:

If we view this in the browser, we get an empty page with an add button in the header. Since we want to populate our list view with data, we should define a Backbone model and collection in order to manipulate and store the data via JavaScript. A basic model and its collection are easily defined:

The great thing about the collection is it provides a RESTful access back to your server for data retrieval and persistence. To keep this simple, our data will be served from a static JSON file with the structure referenced earlier. Since we have no real server side in this example, we can't really save our changes anywhere but in the client's memory. But the collection will fetch the data from the server and can be used to help render our user interface. The following code will create an instance of the collection in memory, retrieve the data from the server, and parse it into a collection of models.

The exercise.initData() function can be called during initialization of the application (or wherever else might be appropriate) to load the data. Now it is time to render the view. Backbone views depend upon Underscore.js. Underscore is a utility library that includes a lot of great features, one of which is view templates. Backbone can be used with many view template frameworks (e.g. Mustache, Handlbars, etc.), but here we will stick with Underscore templates as they meet our needs. For our exercise activity items, we need a very basic template like this:

Giving the template a unique id will let us access it using typical jQuery selectors. The data driven parts of the template are surrounded by

<%= %>
As you can see in line 2, we are using the id, date, and type attributes of whatever model is supplied to the template to fill in the HTML accordingly. While the "identifier" attribute is not a real HTML attribute and not required by any of the frameworks, it would be used to determine what activity the user selected in the list so the appropriate data could be retrieved and displayed on a subsequent page.

The next step is to define the Backbone View that will render the list view. Backbone views can be defined and set up numerous ways, and the documentation does a great job explaining the options, etc. I like to define my views so that they are as self contained as possible. So, rather than allowing Backbone to create the HTML within a DIV (the default behavior), I define the appropriate properties to create a JQM list view as shown in lines 2-4 below:

From the Backbone site: "The default implementation of render is a no-op. Override this function with your code that renders the view template from model data, and updates this.el with the new HTML. A good convention is to return this at the end of render to enable chained calls". The $(this.el) refers to the containing element, in this case the ul element. There are standard attributes that are accessible from within the Backbone View including collection and model. Lines 17-20 iterate over the collection of activities, fills in the template placeholders with the data from the model, and appends the resulting HTML to the containing element.

If you need to pass arbitrary data to your view, it can be accessed via the options object as shown on line 11 of the code snippet. As mentioned earlier, I like my Backbone Views to be as self contained as possible, so I provide the containing HTML element for this view (as a jQuery object) when constructing the View instance. Line 20 sets the HTML of the containing element to the Backbone View and line 21 tells JQM to style things appropriately.

The next step is to instantiate and render the view with the appropriate collection and HTML container. Since this is the "home" page in our application, this is done after JQM initializes the page.

Now we have a list view that renders a JQM list based on data in a Backbone collection. To take advantage of the real power of Backbone models/collections, we can add listeners for changes to the collection that will update the view based on those changes. The beauty of this is the additional code to accomplish this is minimal. By adding

this.collection.bind('add', this.add, this);
to the initialize method of our Backbone View and providing an add() method.

Here we are just grabbing the list view and appending the new model to the view (and refreshing it so JQM does its magic). By adding a click handler to the "Add" button, we can test that adding a model to the collection updates the view.

There are other methods on which to bind, but this provides a quick example on how Backbone can be used to assist with view rendering and data handling in JavaScript based client applications.

The entire code base is available here. It can be deployed on any web server. For OS X, I use the built in web server, but feel free to use the server of your choice.

Related Posts: