One-page Application Development

Exclusive offer: get 50% off this eBook here
HTML5 iPhone Web Application Development

HTML5 iPhone Web Application Development — Save 50%

An introduction to web-application development for mobile within the iOS Safari browser with this book and ebook

$29.99    $15.00
by Alvin Crespo | September 2013 | Open Source Web Development

The article, One-page Application Development, covers iPhone application development using HTML5. This article by Alvin Crespo, author of the book HTML5 iPhone Application Development, looks into deploying a seamless experience in our iPhone application. It also covers the MVC pattern, Backbone.js, and Underscore.js, and an example to enhance it further.

In this article we kick it up a notch by diving into one-page-application development. We've seen this in many of our web applications, including Pandora, Mint, and NPR. We'll cover the foundations of one-page-application development, from an introduction to MVC, Underscore, and Backbone to creating architecture with our sample application and utilizing the methods taught in the first section of this article. Once you complete this article you should have a solid understanding of concepts behind one-page-applications, which will allow you to continue to extend on this knowledge and help guide you on your way to building complex applications. So let's get started by first learning about MVC.

In this article, we will cover:

  • MVC Architecture
  • Introduction to Underscore.js
  • Introduction to Backbone.js
  • Creating a one-page application

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

Model-View-Controller or MVC

Model-View-Controller ( MVC ) is a heavily used design pattern in programming. A design pattern is essentially a reusable solution that solves common problems in programming. For example, the Namespace and Immediately-Invoked Function Expressions are patterns that are used throughout this article. MVC is another pattern to help solve the issue of separating the presentation and data layers. It helps us keep our markup and styling outside of the JavaScript; keeping our code organized, clean, and manageable—all essential requirements for creating one-page-applications. So let's briefly discuss the several parts of MVC, starting with models.

Models

A model is a description of an object, containing the attributes and methods that relate to it. Think of what makes up a song, for example the track's title, artist, album, year, duration, and more. In its essence, a model is a blueprint of your data.

Views

The view is a physical representation of the model. It essentially displays the appropriate attributes of the model to the user, the markup and styles used on the page. Accordingly, we use templates to populate our views with the data provided.

Controllers

Controllers are the mediators between the model and the view. The controller accepts actions and communicates information between the model and the view if necessary. For example, a user can edit properties on a model; when this is done the controller tells the View to update according to the user's updated information.

Relationships

The relationship established in an MVC application is critical to sticking with the design pattern. In MVC, theoretically, the model and view never speak with each other. Instead the controller does all the work; it describes an action, and when that action is called either the model, view, or both update accordingly. This type of relationship is established in the following diagram:

This diagram explains a traditional MVC structure, especially that the communication between the controller and model is two-way; the controller can send data to/from the model and vice versa for the view. However, the view and model never communicate, and there's a good reason for that. We want to make sure our logic is contained appropriately; therefore, if we wanted to delegate events properly for user actions, then that code would go into the view.

However, if we wanted to have utility methods, such as a getName method that combines a user's first name and last name appropriately, that code would be contained within a user model. Lastly, any sort of action that pertains to retrieving and displaying data would be contained in the controller.

Theoretically, this pattern helps us keep our code organized, clean, and efficient. In many cases this pattern can be directly applied, especially in many backend languages like Ruby, PHP, and Java. However, when we start applying this strictly to the frontend, we are confronted with many structural challenges. At the same time, we need this structure to create solid one-page-applications. The following sections will introduce you to the libraries we will use to solve these issues and more.

Introduction to Underscore.js

One of the libraries we will be utilizing in our sample application will be Underscore.js. Underscore has become extremely popular in the last couple of years due to the many utility methods it provides developers without extending built-in JavaScript objects, such as String, Array, or Object. While it provides many useful methods, the suite has also been optimized and tested across many of the most popular web browsers, including Internet Explorer. For these reasons, the community has widely adopted this library and continually supported it.

Implementation

Underscore is extremely easy to implement in our applications. In order to get Underscore going, all we need to do is include it on our page like so:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title></title> <meta name="description" content=""> <meta name="viewport" content="width=device-width"> </head> <body> <script src = "//ajax.googleapis.com/ajax/libs/jquery/
1.9.0/jquery.min.js"></script> <script src = "//cdnjs.cloudflare.com/ajax/libs/underscore.js/
1.4.3/underscore-min.js"></script> </body> </html>

Once we include Underscore on our page, we have access to the library at the global scope using the _ object. We can then access any of the utility methods provided by the library by doing _.methodName. You can review all of the methods provided by Underscore online (http://underscorejs.org/), where all methods are documented and contain samples of their implementation. For now, let's briefly review some of the methods we'll be using in our application.

_.extend

The extend method in Underscore is very similar to the extend method we have been using from Zepto (http://zeptojs.com/#$.extend). If we look at the documentation provided on Underscore's website (http://underscorejs.org/#extend), we can see that it takes multiple objects with the first parameter being the destination object that gets returned once all objects are combined.

Copy all of the properties in the source objects over to the destination object, and return the destination object. It's in-order, so the last source will override properties of the same name in previous arguments.

As an example, we can take a Song object and create an instance of it while also overriding its default attributes. This can be seen in the following example:

<script> function Song() { this.track = "Track Title"; this.duration = 215; this.album = "Track Album"; }; var Sample = _.extend(new Song(), { 'track': 'Sample Title', 'duration': 0, 'album': 'Sample Album' }); </script>

If we log out the Sample object, we'll notice that it has inherited from the Song constructor and overridden the default attributes track, duration, and album. Although we can improve the performance of inheritance using traditional JavaScript, using an extend method helps us focus on delivery. We'll look at how we can utilize this method to create a base architecture within our sample application later on in the article.

_.each

The each method is extremely helpful when we want to iterate over an Array or Object. In fact this is another method that we can find in Zepto and other popular libraries like jQuery. Although each library's implementation and performance is a little different, we'll be using Underscore's _.each method, so that we can stick within our application's architecture without introducing new dependencies. As per Underscore's documentation (http://underscorejs.org/#each), the use of _.each is similar to other implementations:

Iterates over a list of elements, yielding each in turn to an iterator function. The iterator is bound to the context object, if one is passed. Each invocation of iterator is called with three arguments: (element, index, list). If list is a JavaScript object, iterator's arguments will be (value, key, list). Delegates to the native forEach function if it exists.

Let's take a look at an example of using _.each with the code we created in the previous section. We'll loop through the instance of Sample and log out the object's properties, including track, duration, and album. Because Underscore's implementation allows us to loop through an Object, just as easily as an Array, we can use this method to iterate over our Sample object's properties:

<script> function Song() { this.track = "Track Title"; this.duration = 215; this.album = "Track Album"; }; var Sample = _.extend(new Song(), { 'track': 'Sample Title', 'duration': 0, 'album': 'Sample Album' }); _.each(Sample, function(value, key, list){ console.log(key + ": " + value); }); </script>

The output from our log should look something like this:

track: Sample Title duration: 0 album: Sample Album

As you can see, it's extremely easy to use Underscore's each method with arrays and objects. In our sample application, we'll use this method to loop through an array of objects to populate our page, but for now let's review one last important method we'll be using from Underscore's library.

_.template

Underscore has made it extremely easy for us to integrate templating into our applications. Out of the box, Underscore comes with a simple templating engine that can be customized for our purposes. In fact, it can also precompile your templates for easy debugging. Because Underscore's templating can interpolate variables, we can utilize it to dynamically change the page as we wish. The documentation provided by Underscore (http://underscorejs.org/#template) helps explain the different options we have when using templates:

Compiles JavaScript templates into functions that can be evaluated for rendering. Useful for rendering complicated bits of HTML from JSON data sources. Template functions can both interpolate variables, using <%= … %>, as well as execute arbitrary JavaScript code, with <% … %>. If you wish to interpolate a value, and have it be HTML-escaped, use <%- … %>. When you evaluate a template function, pass in a data object that has properties corresponding to the template's free variables. If you're writing a one-off, you can pass the data object as the second parameter to template in order to render immediately instead of returning a template function.

Templating on the frontend can be difficult to understand at first, after all we were used to querying a backend, using AJAX, and retrieving markup that would then be rendered on the page. Today, best practices dictate we use RESTful APIs that send and retrieve data. So, theoretically, you should be working with data that is properly formed and can be interpolated. But where do our templates live, if not on the backend? Easily, in our markup:

<script type="tmpl/sample" id="sample-song"> <section> <header> <h1><%= track %></h1> <strong><%= album %></strong> </header> </section> </script>

Because the preceding script has an identified type for the browser, the browser avoids reading the contents inside this script. And because we can still target this using the ID, we can pick up the contents and then interpolate it with data using Underscore's template method:

<script> function Song() { this.track = "Track Title"; this.duration = 215; this.album = "Track Album"; }; var Sample = _.extend(new Song(), { 'track': 'Sample Title', 'duration': 0, 'album': 'Sample Album' }); var template = _.template(Zepto('#sample-song').html(), Sample); Zepto(document.body).prepend(template); </script>

The result of running the page, would be the following markup:

<body> <section> <header> <h1>Sample Title</h1> <strong>Sample Album</strong> </header> </section> <!-- scripts and template go here --> </body>

As you can see, the content from within the template would be prepended to the body and the data interpolated, displaying the properties we wish to display; in this case the title and album name of the song. If this is a bit difficult to understand, don't worry about it too much, I myself had a lot of trouble trying to pick up the concept when the industry started moving into one-page applications that ran off raw data (JSON).

For now, these are the methods we'll be using consistently within the sample application to be built in this article. It is encouraged that you experiment with the Underscore.js library to discover some of the more advanced features that make your life easier, such as _.map, _.reduce, _.indexOf, _.debounce, and _.clone. However, let's move on to Backbone.js and how this library will be used to create our application.

HTML5 iPhone Web Application Development An introduction to web-application development for mobile within the iOS Safari browser with this book and ebook
Published: May 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Introduction to Backbone.js

To add structure to our one-page application, we will be using Backbone.js, a light framework that helps us apply the MVC design pattern. Backbone.js is one of the many MVC-type frameworks that help frontend development stick to best practices of separating out the data from the views or in particular, the DOM. On top of that, our applications can become quite complex for one-page apps. Backbone.js helps alleviate these issues and gets us going quickly. So let's start with discussing how MVC applies to this framework.

MVC and Backbone.js

There are many types of JavaScript frameworks that apply MVC differently, it is no different for Backbone. Backbone implements Models, Views, Collections, and Routers; it also includes an Event, History, and Sync system. As you can see, Backbone does not have a traditional Controller that was discussed earlier, but we can interpret Views as controllers. As per Backbone's documentation (http://backbonejs.org/#FAQ-mvc):

(…) in Backbone, the View class can also be thought of as a kind of controller, dispatching events that originate from the UI, with the HTML template serving as the true view.

This type of MVC implementation can be a bit confusing, however our sample application will help clear things up. For now let's dive into Backbone models, views, and collections. In the following sections we'll go over how each part of Backbone gets implemented and the parts we'll be using to build our application.

Backbone models

As in any MVC pattern, the Model is critical, containing the data and logic, including properties, access controls, conversions, validations, and more. Keep in mind that we write models on a daily basis, and in fact we have created a number of models throughout this article (MediaElement, Video, Audio, and so on). Backbone models are similar to a boilerplate in that they provide utility methods that we would otherwise have to build ourselves.

Let's take the following code as an example:

function Song() { this.track = "Track Title"; this.duration = 215; this.album = "Track Album"; }; Song.prototype.get = function(prop) { return this[prop] || undefined; } Song.prototype.set = function(prop, value) { this[prop] = value; return this; } var song = new Song(); song.get('album'); // "Track Album" song.set('album', 'Sample Album'); // Song song.get('album'); // "Sample Album"

In the preceding example, we have created a Song model, the same as in the previous section, that has several properties (track, duration, and album) and methods (get and set). From there we create an instance of Song and use the methods created to get and set the album property. This is great; however, we needed to create those methods manually. That is not what we want to do; we already know we need those methods, so we just want to focus on the data and extending it. This is where Backbone models come into play.

Let's analyze the following Model:

var SongModel = Backbone.Model.extend({ 'defaults': { 'track': 'Track Title', 'duration': 215, 'album': 'Track Album' } }); var song = new SongModel(); song.get('album'); // "Track Album" song.set('album', 'Sample Album'); // SongModel song.get('album'); // "Sample Album"

The preceding code shows how quickly we get off the ground writing our applications. Behind the scenes, Backbone is a namespace and has a model object attached to it. Then, using Underscore's extend method, we return a copy of Backbone.Model, that has merged default properties attached to it, to the variable SongModel. Then we do the same as earlier, using get and set, with the desired output in the comments.

As you can see it's pretty simple to get started using Backbone, especially if you just wanted a way to organize your data without building custom functionality for each and every application. Now let's look at views inside Backbone and how it can actually help us separate the data from our UI.

Backbone views

Backbone views are a bit different than models in such a way that they are more for convenience. If we look at the Backbone documentation and compare the Views and Models sections, we'll find that Views are a bit more bare bones, but again are useful in organizing our applications. To see why these are still useful, let's look at the following code:

var $section = $('section'); $section.on('click', 'a', doSomething); function doSomething() { // we do something here }

Typically, this is how we would cache our elements on the page and delegate events for particular user interactions. However, what if this could be done with less setup work? In the following code, we transform the preceding code into a typical Backbone view setup.

var SongView = Backbone.View.extend({ 'el': document.querySelector('section'), 'events': { 'click a': 'doSomething' }, 'doSomething': function(e){ console.log($(e.currentTarget).attr('href')); } }); var view = new SongView();

As you can see, Backbone takes care of the setup work for you. It caches the element selected and delegates the events for you behind the scenes. Literally, all you need to do on your end is the setup and quickly move on to the next step; now you'll notice that your development time decreases while your efficiency increases, and this is just the preliminary steps into Backbone. Now, the magic happens when we connect the Model and View together. To see this in action, take a look at the following code:

var SongModel = Backbone.Model.extend({ 'defaults': { 'track': 'Track Title', 'duration': 215, 'album': 'Track Album' } }); var song = new SongModel(); var SongView = Backbone.View.extend({ 'el': document.querySelector('section'), 'events': { 'click a': 'doSomething' }, 'initialize': function() { this.model.on('change:track', this.updateSongTitle, this); this.$el.$songTrack = this.$el.find('.song-track'); this.$el.$songTrack.text(this.model.get('track')); }, 'doSomething': function(e){ console.log($(e.currentTarget).attr('href')); }, 'updateSongTitle': function() { this.$el.$songTrack.text(this.model.get('track')); } }); var view = new SongView({ 'model': song }); song.set('track', 'Sample Track'); // The DOM Updates with the right value

In this code snippet we have finally connected a single model to one view. The way we have done this is by passing in the instance of the model into the instance of the view:

var view = new SongView({ 'model': song });

When we do this, we associate the Model and the View. But we also need to do something with that Model, and usually we want to display the data associated with it. So in this example, we create an initialize method that gets called as a constructor. In this method, we use Backbone's built-in event system to track any changes associated with the Model's track property and call updateSongTitle accordingly. While we're at it, we change the context of the event handler by passing in this as the third parameter and then cache the element displaying the song's track.

In the end, when you change the instance of the song's track property, the DOM updates accordingly. We now have the basics we need to build our application. But let's take a look at Backbone collections to understand how keeping track of our data increases the efficiency of our application.

Backbone collections

Now, up until this point we have worked with a single Model, which is great but in most cases we work with sets of data. This is why Backbone collections exist, to manage an ordered set of models. Backbone collections also tie into Underscore's methods, allowing us to work with these sets easily and efficiently with no setup work.

Let's look at the following code:

var SongModel = Backbone.Model.extend({ 'defaults': { 'track': 'Track Title', 'duration': 215, 'album': 'Track Album' } }); var SongCollection = Backbone.Collection.extend({ 'model': SongModel }); var SongView = Backbone.View.extend({ 'el': document.querySelector('section'), 'events': { 'click a': 'doSomething' }, 'initialize': function() { this.collection.on('change', this.updateDetected, this); }, 'doSomething': function(e){ console.log($(e.currentTarget).attr('href')); }, 'updateDetected': function() { console.log("Update Detected"); } }); var collection = new SongCollection(); for (var i = 0; i < 100; i++) { collection.add(new SongModel()); } var view = new SongView({ 'collection': collection });

This sample code is very similar to the code produced in the previous section. The difference here is that we have created a SongCollection that takes models of type SongModel. Then we create an instance of this collection, add 100 models to it via our for loop, and finally attach the collection to our View.

Our View has also changed in such a way that we have attached the change event to our collection, and created a more general listener that gets called whenever a Model is updated within the collection. Therefore, when we execute the following code the View lets us know that something was updated:

collection.models[0].set('album', 'sample album'); // "Update Detected"

Server-side interactions

It's not easy seeing how a Backbone application connects to the server, especially since we have so much going on in the frontend code. But, if YOU take a look at the documentation provided on the Backbone.js website (http://backbonejs.org/#Sync), we know that Models contain all the functionality for manipulating the data. In fact, Models connect to the database and can sync with it.

Backbone.sync is the function that Backbone calls every time it attempts to read or save a model to the server. By default, it uses (jQuery/Zepto).ajax to make a RESTful JSON request and returns a jqXHR. You can override it in order to use a different persistence strategy, such as WebSockets, XML transport, or Local Storage.

But, Models aren't the only ones that can connect to the server. As the documentation continues to read, a model or collection can begin a sync request and interact with it accordingly. This is a bit different than a traditional MVC implementation, especially since collections and models can interact with the database. To better display Backbone's implementation of MVC, the provided image helps display the relationship between the different types of objects:

This is pretty much what we have created previously; a view, model, and controller. The implementation is slightly different, but we can see that there is a clear separation between the presentation layer and data because the view never directly interacts with the database. If this is a bit confusing, it's because it is and is another level of complexity that, when understood, will help guide you to coding Zen.

You are now fully prepared to create a one-page application using Underscore, Backbone, and Zepto. But, there is a problem. These libraries help speed up our development and increase efficiency, but don't actually provide a solid structure for our applications. This is what we tackle in our sample application. Next, we will discuss architecture, implementation, and optimization needed for one-page applications.

Summary

This article provided an introduction to the MVC pattern, Backbone.js, and Underscore.js, which helps in developing one-page applications. It also covers the various principles of the aforementioned topics.

Resources for Article:


Further resources on this subject:


HTML5 iPhone Web Application Development An introduction to web-application development for mobile within the iOS Safari browser with this book and ebook
Published: May 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Alvin Crespo

Alvin Crespo is a creative technologist strongly focused on delivering compelling user experiences through the use of frontend technologies. Utilizing the latest industry standards, he strives to move the Web forward promoting open source technologies. Having worked in startup and agency environments, he has helped build and architect complex applications for both medium and large-sized companies.

Books From Packt


Responsive Web Design with HTML5 and CSS3
Responsive Web Design with HTML5 and CSS3

Responsive Web Design by Example
Responsive Web Design by Example

HTML5 and CSS3 Responsive Web Design Cookbook
HTML5 and CSS3 Responsive Web Design Cookbook

HTML5 Games Development by Example: Beginner’s Guide
HTML5 Games Development by Example: Beginner’s Guide

HTML5 Multimedia Development Cookbook
HTML5 Multimedia Development Cookbook

 HTML5 Mobile Development Cookbook
HTML5 Mobile Development Cookbook

HTML5 Graphing and Data Visualization Cookbook
HTML5 Graphing and Data Visualization Cookbook

Instant HTML5 Geolocation How-to [Instant]
Instant HTML5 Geolocation How-to [Instant]


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