Routeless Backbone Contacts

Sep 23, 2011 Backbone.jscoffeescript

You don’t need a URL router to write client-side applications.

Routeless Backbone.js Contacts is a totally client-side CRUD tutorial application written using CoffeeScript, Stylus, Backbone.js and jQuery which are a perfect match for writing concise, readable well structured web applications.

Note: This release described in this post is at the 1.0 tag.

Note: A second version of this tutorial application [has been posted], it builds on the material covered in this post.

Screenshots

ListContactView

contacts-list.png

ShowContactView

contacts-show.png

EditContactView

contacts-edit.png

Going routeless

It’s a mindset thing. If you come from a server-side web applications background your first instinct is to use a router and fragment identifiers to emulate browser page navigation – go down this route you soon find that trying to maintain a consistent back-button browser history is time consuming, messy and ultimately unnecessary. Single page applications don’t need a back-button (or any browser chrome), especially if they are bundled as pseudo-native mobile apps with something like PhoneGap or packaged for the desktop, for example as Google Chrome Packaged Apps.

Routeless Backbone.js Contacts resides at a single unfragmented URL – user interface navigation is managed exclusively by DOM events. Button and link elements deal with the click events client-side (you are not POSTing form data to a server, so form elements and submit buttons are not necessary). If the application were to persist data externally then then the data POSTS and GETS would be handled transparently by a Backbone database adapter.

Running the application

Once you have downloaded the source from Github open the index.html file in your browser. Press the Import Data button to load the example contacts database.

Important: Unlike Google Chrome, neither Firefox 6 or IE9 like persisting Web Storage from file based URLs and you will need to open the application via a web server. I use Mongoose (a neat little single-executable cross-platform web server) for testing. Once you’ve installed mongoose:

The source

This post should be read side-by-side with the source, it’s very readable (although a basic understanding of CoffeeScript, HTML and jQuery is recommended).

index.html Application page HTML and view templates. application.coffee Application, models and views. data.js Canned data (100 fictitious contacts) loaded by the Import Data command. main.styl Stylus CSS. helpers.styl, gradients.styl CSS helper functions.

HTML5 markup is used throughout. All the logic is confined to application.coffee (around 160 lines of code). The beauty of CoffeeScript is that the code is concise and virtually self-documenting, for example, here’s the event handler in the ListContactView that responds to the Clear All button click:

clear: (e) ->
    return if not confirm 'About to delete all data.'
    contact.destroy() for contact in @collection.toArray()
    @render()

Application structure

The app object

There is a single global instance app of the App class which:

Models and Collections

A single app.contacts collection of Contact models is persisted locally using the Backbone localStorage Adapter. A single store is instantiated and attached to the ContactModel, the same store is referenced by the ContactCollection.

Views

The CRUD user interface is implemented by three Backbone.js views – ListView, ShowView and EditView (the EditView is also used to create new contacts).

This example (from the ListContactView) uses a custom data attribute (data-id) to pass the contact ID from the anchor element via a click event object.

DOM event registration:

events:
    'click a.show': 'show'

Link click handler:

show: (e) ->
    @model = @collection.get e.target.getAttribute('data-id')
    @render()

Template link markup:

<a class="show" data-id="<%= contact.id %>"><%= contact.getName() %></a>

It would have been nice to have used the HTML5 DOM dataset property to retrieve the data-id attribute (e.target.dataset.id) but it does not currently work in IE9, Safari or Android browsers.

Libraries

The app uses the following JavaScript libraries (in the lib directory):

Techniques

Load scripts at the end of the page body

Place script tags last in the page body, just before the closing body tag. This ensures the page elements elements have been parsed and can be referenced when the scripts execute and allows you to safely reference page elements from class property initializers. See this stackoverflow discussion.

Intra-application links do not need href’s

Dropping the href ensures there are no changes to the browser URL or history.

CSS and HTML Tips

  * {
    font-size: 20px;
    font-family: sans-serif;
    margin: 0;
    padding: 0;
  }

References

« Previous Next »