Home Programming Backbone.js Patterns and Best Practices

Backbone.js Patterns and Best Practices

By Swarnendu De
books-svg-icon Book
eBook $25.99 $17.99
Print $43.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $25.99 $17.99
Print $43.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Reducing Boilerplate with Plugin Development
About this book
Publication date:
January 2014
Publisher
Packt
Pages
174
ISBN
9781783283576

 

Chapter 1. Reducing Boilerplate with Plugin Development

"When working on a web application that involves a lot of JavaScript, one of the first things you learn is to stop tying your data to the DOM. It's all too easy to create JavaScript applications that end up as tangled piles of jQuery selectors and callbacks, all trying frantically to keep data in sync between the HTML UI, your JavaScript logic, and the database on your server. For rich client-side applications, a more structured approach is often helpful."

The previous excerpt from http://backbonejs.org precisely specifies the problem that Backbone.js solves. Backbone.js provides a way to simplify the JavaScript application structure, which was clearly a nightmare, even a few years ago. Today, we have moved a long way from tightly coupled jQuery-based applications to heavy frontend applications, and a major portion of the application logic now relies on the UI part. This means organizing the application structure is now one of the most significant aspects of application development, and should take care of the reusability, modularity, and testability of the components of an application.

Being an extremely lightweight library, Backbone.js, along with the utility library Underscore.js, provides a set of tools that help to organize your code and makes it easier to develop single-page web applications. Backbone delivers a minimalistic solution to separate the concerns of your application; features include RESTful operations, persistent strategies, models, views with logic, event-driven component communication, templating, and routing facilities. Its simplistic nature, excellent documentation, and a large community of developers make it easy to learn how to use this library.

However, to develop a robust system, we do not depend only on the basic functional components of the framework; we have to use many other libraries, plugins, and reusable add-ons to support the core system as well. While Backbone.js with its core components provides a way to structure your application at the base level, it is really not enough until we either develop our own or use other open source extensions, plugins, and useful patterns. In order to create solid, software architecture, we need to make the best use of existing components and follow proper design patterns. This is what we intend to deliver in this book.

This is not a general introduction book, and we expect our readers to have a basic understanding of the Backbone.js framework. If you are a beginner and looking for good resources to start with Backbone.js, we will recommend you to refer Appendix A, Books, Tutorials, and References, of this book, where we listed a number of useful resources to help you master Backbone.js.

We will start with an understanding of how we can re-use our code and reduce a boilerplate by developing custom extensions, plugins, and mixins. In the latter chapters, we will start discussing the common problems, tips, patterns, best practices, and open source plugins for each Backbone.js component. We will also see how we can use Backbone.js to structure and architect complex web applications, and understand the basics of unit testing in JavaScript-based applications. In addition, instead of developing a single application spanning all the chapters, we have tried to provide simple and complete examples on each topic separately throughout this book. In this chapter, we will learn a few important topics with examples. These topics and concepts will be used many times in rest of the chapters. They are as follows:

  • Basic components of Backbone.js: This consists of a brief discussion about the definitions of the Backbone components

  • Use of Underscore.js: This consists of a brief discussion about Underscore.js and the utility of using this library for JavaScript-based projects

  • Re-use code with extensions: This consists of reusing the Backbone code by moving common code blocks to parent-level classes

  • Backbone mixins: This consists of an explanation of what mixin is, and how and where to use mixins with Backbone

 

Basic components of Backbone.js


We will look into some basic concepts of Backbone.js and Underscore.js before moving to the plugin development section. Backbone.js is a client-side MV* framework that provides a set of tools and building blocks required to structure a JavaScript application. Important tools that Backbone.js offers are as follows:

  • Backbone.Model: Models are the entity of an application that store data and contain some logic around data such as validation, conversion, and data interaction.

  • Backbone.View: Views present an idea of organizing your Document Object Model (DOM) interface into logical blocks, and represent the model and collection data in them. Views are excellent tools to organize all the JavaScript event handlers and to add dynamic HTML content in your application via optional use of JavaScript templates. As Backbone follows an MV* pattern, Backbone views mostly work as presenters and take care of the major portion of application functionality.

  • Backbone.Collection: A collection is a group of models. A collection includes a lot of functionality as well as Underscore utility methods to help you work on multiple data models.

  • Backbone.Router: A router provides methods for routing client-side pages and acts subsequently whenever there is a change in the browser's URL. A router maintains the application state as per the URL change.

  • Backbone.Events: Events are an important concept in Backbone, since they provide a mechanism to use the PubSub pattern and decouple your application components.

Apart from these, there are other tools such as Backbone.History, which manages the browser history and the back/forward buttons in accordance with the routers. Also, we have Backbone.Sync, which is a single method that provides a nice abstraction to the network access through Backbone models and collections.

 

Using Underscore.js


Underscore.js (http://underscorejs.org/) is a powerful utility library that provides a lot of functional programming support for your JavaScript code. In general, JavaScript comes up with a very low number of utility methods on its own, and most of the time we need to either develop our own functions or depend on another library for these methods. Underscore comes up with a bagful of highly efficient utility methods, which makes it an excellent tool for your JavaScript projects. The functions it provides can be grouped into the following sections:

  • Collections (Array or Object)

  • Arrays

  • Functions

  • Objects

  • Utility

  • Chaining

These include functions for iterations, sorting, filtering, conversions, templating, comparisons, scope binding, and many more. The main benefits of using this small library are as follows:

  • It helps you to make the JavaScript code more intuitive and concise.

  • In addition to the convenient methods, Underscore also implements cross-browser versions of newer JavaScript functions, which are only available in modern browsers. Underscore will detect whether the browser supports the method, and will use the native implementation if it is present. This boosts the function's performance to a great extent.

  • The minified and gzipped version of the library weighs only 4.9 KB, which leaves little excuse for not taking advantages of this library.

  • The library is completely DOM-free—so you can use it for your server-side JavaScript code as well.

  • Excellent documentation similar to Backbone.js with examples is available at http://underscorejs.org/.

Backbone.js has a hard dependency on Underscore.js, and you are bound to use it if you are developing your applications with Backbone.js. However, even when you are not using Backbone, we encourage you to use Underscore.js for your JavaScript projects. It adds no overhead, integrates easily, and makes your code more robust even when you are not aware of all the underlying engineering principles employed by this library.

There is another library named Lo-dash (http://lodash.com), which provides an Underscore built to perform drop-in replacement of the Underscore.js library. It is said to have a slightly better performance than Underscore.js. You can try either of them to achieve the same result.

 

Re-using code with extensions


Backbone is quite a small library in comparison with other libraries. Any complex application can be structured and developed with Backbone, but the framework itself doesn't come with prebuilt widgets or reusable UI components. In this section, we will talk about some Backbone and JavaScript techniques that will help you build a reusable interface library.

For simple and small applications, code reusability doesn't always seem much of a necessity. But as you proceed to create an application with multiple views, models, and collections, you find that a certain portion of your code gets repeated several times. Creating reusable extensions and plugins in such cases improves the performance of the application by enhancing modularity and reducing the code size. Let's create a simple Backbone view to understand how we can create an extension, shown in the following code snippet:

var User = Backbone.Model.extend({
  defaults: {
    name: 'John Doe'
  }
});

var UserItemView = Backbone.View.extend({
  template: '<span><%= name %></span>',
  render: function () {
    var tpl = _.template(this.template),
      html = tpl(this.model.toJSON());

    this.$el.html(html);
    return this;
  }
});

// Create a view instance passing a new model instance
var userItem = new UserItemView({
  model: new User
});

$(document.body).append(userItem.render().el);

The view named UserItemView is a simple Backbone view where we want to display our model data inside a template and append this view element to the DOM. This is a fundamental functionality of Backbone where the primary requirement is to display a model's data as a view. If we have another similar view with a model, and this has the same functionality, the render() function will also be identical. That said, won't it be beneficial if we move the common code to a base class and extend that class to inherit the functionality? The answer is yes. Let's see how we can do that in the example in the following section.

Creating a base class

We create a BaseView class where common functionality such as the render() method is added. Then all other view classes can extend from this base class, and eventually inherit the rendering functionality. The following is the BaseView class with minimal rendering functionality:

// Parent view which has the render function
var BaseView = Backbone.View.extend({
  render: function () {
    var tpl = _.template(this.template),
      data = (this.model) ? this.model.toJSON() : {},
      html = tpl(data);

    this.$el.html(html);
    return this;
  }
});

Now, UserItemView will look much better. We will extend the BaseView class and will provide only the template as follows:

// A simpler view class
var UserItemView = BaseView.extend({
  template: '<span><%= name %></span>'
});

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

If you wish to add some extra functionality such as calling another function in your view's render() method, you can override the render method of the base class. Check the following example:

var UserItemView = BaseView.extend({
  tagName: 'div',
  template: '<span><%= name %></span>',
  render: function () {
    // Call the parent view's render function
    BaseView.prototype.render.apply(this, arguments);

    // Add your code here
    this.anotherFn();
    return this;
  },

  anotherFn: function () {}
});

There are a number of functionalities that you can move to your base class depending on your requirements. For example, in a non-trivial application, we often need to replace a view with another, destroy the old view by removing it from DOM, and clean up other dependencies. So, we can add a close() method to BaseView (as shown in the following code) that can take care of every view removal mechanism.

var BaseView = Backbone.View.extend({
  render: function () {
    var tpl = _.template(this.template),
      data = (this.model) ? this.model.toJSON() : {},
      html = tpl(data);

    this.$el.html(html);
    return this;
  },

  close: function () {
    // Extra stuff goes here

    // Remove the view
    this.remove();
  }
});
// This is not production-ready code, but it clearly gives you the concept of using custom widgets to reduce boilerplate in your code. It will not always be necessary to extend a Backbone class to create a plugin.

Developing plugins without extending base classes

Sometimes we find that creating a constructor function and adding methods to its prototype can be a better choice than extending the Backbone base classes. For example, in the Pagination plugin in the following code, instead of creating a PaginationCollection class by extending Backbone.Collection, we will prefer to go for a simpler class—a constructor function that accepts two arguments: a collection and the number of the items to be shown in a page.

// Pagination constructor function
var Pagination = function (collection, noOfItemsInPage) {
  if (!collection) {
    throw "No collection is passed";
  }
  this.currentPage = 1;
  this.noOfItemsInPage = noOfItemsInPage || 10;
  this.collection = collection;
}

// Use Underscore's extend method to add properties to your plugin
_.extend(Pagination.prototype, {
  nextPage: function () {},
  prevPage: function () {}
});

var User = Backbone.Model.extend({
  defaults: {
    name: 'John Doe'
  }
});

var Users = Backbone.Collection.extend({
  model: User
});

var paging1 = new Pagination(10, new Users());
var paging2 = new Pagination(20, new Users());

We didn't add the actual functionality, but just showed a skeleton of how the Pagination class may look. The benefit can be observed when you already have a collection and you want to implement pagination without extending a parent collection class. We added the member variables in constructor function so that individual instances of this class can have their own set of variables. On the other hand, the methods are added to the prototype of the class so that they are shared by all instances of the class.

This mechanism can be useful when you need a custom plugin that is not a type of Backbone view, model, or collection.

 

Understanding JavaScript mixins


In the previous section, we saw that inheriting properties from a parent class prototype provides a great deal of reusability. In some cases, we may want to re-use similar methods in multiple views, models, or collections. This can be achieved by creating a parent class that they can extend; however, it is not always a good practice as it creates some unnecessary layers and meaningless subtypes.

For example, assume that you want the view element of UserItemView, which already extends BaseView, to be draggable. So you include a DraggableView class that extends the BaseView class, and your UserItemView extends DraggableView. Now there is a sudden change in the requirement and you are asked to make the view named UserItemView a sortable view as well. Will you introduce another new class, SortableView, and put it somewhere in the chain? If yes, then this multitiered inheritance will surely create a logic that is absolutely unmanageable and frustrating. Look at the following figure that describes the situation in a better way:

What is a mixin?

Fortunately, there is a feasible alternative in JavaScript, which is called m ixin. In general computer science, a mixin is a class that provides a set of functions relating to a particular type. These mixin classes are not instantiated, but their functions are just copied to the main class to achieve a similar inheriting behavior without entering into the inheritance chain. Look at the following figure to understand the concept:

We have a ListItemView class that extends the BaseView class and represents an individual item of a list. Now we want these items to be draggable. How we can achieve this? How about adding a few methods in the ListItemView class that will take care of the dragging functionality? This approach will work, but what if we have few more components that need to be draggable too? Then we have to make a reusable object with these methods and use that object in all the required classes. This is what the mixin concept is—a collection of methods that will be copied to the class that wants this functionality.

Creating classic mixins

The most basic mixin definition will be a simple object with some properties such as the following code snippet:

// A simple object with some methods
var DraggableMixin = {
  startDrag: function () {
    // It will have the context of the main class 
    console.log('Context = ', this);
  },
  onDrag: function () {}
}

// UserItemView already extends BaseView
var UserItemView = BaseView.extend({
  tagName: 'div',
  template: '<%= name %>'
});

We will use the Underscore method, _.extend(), to copy the mixin properties to the main class's prototype:

// We just copy the Mixin's properties into the View
_.extend(UserItemView.prototype, DraggableMixin, {
  otherFn: function () {}
});

var itemView = new UserItemView();

// Call the mixin's method
itemView.startDrag();

Note that the drag-related methods are now copied from DraggableMixin to its prototype. Similarly, we can use the same _.extend() method to copy the methods of SortableMixin to implement the sortable behavior without creating any multilayered inheritance.

Sometimes you may not want to copy all the methods of a mixin in your class. In that case, simply create a property in your class and copy the required function from the mixin in that property:

UserItemView.prototype.startDrag = DraggableMixin.startDrag;

This is helpful when you need only a part of the functionality from the mixin.

Creating functional mixins

There are some other ways of defining a mixin too. The following is an example of a functional pattern:

// Functional mixin
var DraggableMixin = function (config) {
  this.startDrag = function () {};
  this.onDrag = function () {};

  return this;
}

// DraggableMixin method is called passing the config object 
DraggableMixin.call(UserItemView.prototype, {
  foo: 'bar'
});
// SortableMixin.call(UserItemView.prototype);

new UserItemView().startDrag();

The mixin here works as a verb, and this functional approach is well accepted in the community. The this function always refers to the receiver, that is, UserItemView. The functionality is exactly same but with a major difference—the _.extend() method is no longer needed and the mixin methods are not copied this time but are cloned instead. This is not a major problem—just the functions are redefined every time the mixin is used. However, this can also be minimized by caching the functions within the mixin. Let's see how we can achieve that in the next section.

Caching mixin functions

We can cache the initial function definitions by wrapping up the mixin in a closure:

// Functional mixin with cache
var DraggableMixin = (function () {
  var startDrag = function () {};
  var onDrag = function () {};

  return function (config) {
    this.startDrag = startDrag;
    this.onDrag = onDrag;

    return this;
  };
})(); 

The closure executes only once to define the methods even if the mixin is called several times. However, it raises another concern—inside the mixin methods, how are we going to use the config object that we are passing? This issue can be resolved by using an interesting pattern named curry.

Using curry to combine a function and arguments

As described by Douglas Crockford in his book Javascript: The Good Parts:

"Currying allows us to produce a new function by combining a function and an argument."

Assume that you have a function and a set of arguments. You want these arguments to be combined with the function someway, so that when you will call that function without passing anything, the arguments will still be available to the function. See the following example:

// Simple function
function foo(){
  console.log(arguments);
}


// We want this bar object to be available in the foo() function
var bar = {
  name: 'Saswata Guha'
};

// Calling foo() without passing anything. Using curry, the 
// function will have the bar object in its scope
foo();  

The curry() pattern's definition is quite simple where this method is added to the function prototype, so when it is called on any function, it merges the arguments passed to itself with the arguments of the main function, as shown in the following code snippet:

// Definition of curry
Function.prototype.curry = function () {
  var slice = Array.prototype.slice,
    args = slice.apply(arguments),
    that = this;
  return function () {
    return that.apply(null, args.concat(slice.apply(arguments)));
  };
};

Now let's see how we can apply curry to our DraggableMixin function, so that the config object is available to all its methods, as shown in the following code snippet:

// Functional mixin with cache
var DraggableMixin = (function () {
  var startDrag = function (options) {
    console.log('Options = ', options);
  };
  var onDrag = function () {};

  return function (config) {
    this.startDrag = startDrag.curry(config);
    this.onDrag = onDrag;

    return this;
  };
})();

DraggableMixin.call(UserItemView.prototype, {
  foo: 'bar'
});

So, when we call curry on the startDrag() method, we pass the config object that we received while applying mixin, and it becomes available to startDrag as an argument. You can use either the classic or functional approaches for defining a mixin, though I personally prefer the latter.

Mixin is an important concept that many popular JavaScript libraries such as Sencha and Dojo follow. While the concept is quite easy, finding a proper context in an application to use a mixin is bit difficult. However, once you are aware of its use, you may soon find it beneficial to enforce reusability in your application.

 

Summary


If you ever checked the annotated source code (http://backbonejs.org/docs/backbone.html) of Backbone, you might have found that the library footprint is very small (the production file is only 6.4 KB at v1.1.0). Its sole purpose is to improve the structure and maintainability of your code with the least complexity. So, once you start using Backbone, you will find that in every step of the development, you need to write custom widgets and plugins. In this chapter, we learned the basics of Backbone.js and the utility of using Underscore.js with Backbone.js. We also saw how developing reusable components and custom pugins can reduce boilerplate from our code. In the end, we understood the concept of JavaScript plugins and discussed different approaches for defining mixins. We are going to use all these concepts several times in the following chapters.

In the next chapter, we will discuss different problems associated with Backbone views and possible solutions to them. We will also see how custom-view plugins or mixins can solve most of the problems.

About the Author
  • Swarnendu De

    Swarnendu De is the director of Innofied Solution Pvt. Ltd.( http://www.innofied.com ), a specialized mobile, web, and game development company. He manages technical operations and leads the JavaScript development team there. For the last seven years, he has been working with numerous JavaScript technologies including Backbone.js, Node.js, ExtJS, Sencha, and so on, and has developed more than 50 complex JavaScript-based applications thus far. He regularly writes at his personal blog, company blog, and the Tuts+ network. He has been working with Backbone.js for the last 2 years and has developed multiple, large, and complex Backbone.js-based applications using this technology. Swarnendu lives in Kolkatathe city of joy. He loves travelling, photography, and spending time with his family. You can reach him through his website at http://www.swarnendude.com or via Twitter at @swarnendude.

    Browse publications by this author
Backbone.js Patterns and Best Practices
Unlock this book and the full library FREE for 7 days
Start now