Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Backbone.js Patterns and Best Practices
Backbone.js Patterns and Best Practices

Backbone.js Patterns and Best Practices: Improve your Backbone.js skills with this step-by-step guide to patterns and best practice. It will help you reduce boilerplate in your code and provide plenty of open source plugin solutions to common problems along the way.

By Swarnendu De
€25.99 €17.99
Book Jan 2014 174 pages 1st Edition
eBook
€25.99 €17.99
Print
€32.99
Subscription
€14.99 Monthly
eBook
€25.99 €17.99
Print
€32.99
Subscription
€14.99 Monthly

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details


Publication date : Jan 24, 2014
Length 174 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781783283576
Category :
Table of content icon View table of contents Preview book icon Preview Book

Backbone.js Patterns and Best Practices

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.

Left arrow icon Right arrow icon

Key benefits

What you will learn

Develop custom plugins and mixins to reduce boilerplate in your code Learn about Backbone view management with nested views, subviews, layout manager, and Marionette views Understand template management by storing and precompiling templates Explore model validation with validation plugins and learn model serialization and relational data management with nested models Work with collections to implement multiple sorting and filtering behavior Create solid application architecture with AMD and different popular design patterns

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details


Publication date : Jan 24, 2014
Length 174 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781783283576
Category :

Table of Contents

19 Chapters
Backbone.js Patterns and Best Practices Chevron down icon Chevron up icon
Credits Chevron down icon Chevron up icon
About the Author Chevron down icon Chevron up icon
Acknowledgments Chevron down icon Chevron up icon
About the Reviewers Chevron down icon Chevron up icon
www.PacktPub.com Chevron down icon Chevron up icon
Preface Chevron down icon Chevron up icon
1. Reducing Boilerplate with Plugin Development Chevron down icon Chevron up icon
2. Working with Views Chevron down icon Chevron up icon
3. Working with Models Chevron down icon Chevron up icon
4. Working with Collections Chevron down icon Chevron up icon
5. Routing Best Practices and Subrouting Chevron down icon Chevron up icon
6. Working with Events, Sync, and Storage Chevron down icon Chevron up icon
7. Organizing Backbone Applications – Structure, Optimize, and Deploy Chevron down icon Chevron up icon
8. Unit Test, Stub, Spy, and Mock Your App Chevron down icon Chevron up icon
Books, Tutorials, and References Chevron down icon Chevron up icon
Precompiling Templates on the Server Side Chevron down icon Chevron up icon
Organizing Templates with AMD and Require.js Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Filter icon Filter
Top Reviews
Rating distribution
Empty star icon Empty star icon Empty star icon Empty star icon Empty star icon 0
(0 Ratings)
5 star 0%
4 star 0%
3 star 0%
2 star 0%
1 star 0%

Filter reviews by


No reviews found
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.