Exploring Drupal 8 Notes - Backbone.js

At the time of writing, apart from breezing through a few tutorials, I have not implemented anything with Backbone.  I am making these notes as a reference overview of how Backbone works.  When I get to D8 module development, if feasible, I may write a tutorial on how to incorporate Backbone into a Drupal module.

What it is

Backbone.js is a JavaScript library with lots of helpful functions for building and organizing rich JavaScript interfaces.  Based on an MVC pattern, the library helps you create clean, efficient code.  Its code base is very small considering the functionality and extensibility it provides.  It is meant to be the backbone of your front end application.  It does a few important things well but leaves much of the decision as to how you want to use the library up to the developer.

What is is not

Although it is often compared with popular frameworks and mistakenly called a framework, Backbone is not a framework; it is a library.  It is also not a true MVC because it doesn’t have a controller.  MV* would be more accurate.

The difference between frameworks and libraries

The terms framework and library are often used interchangeably but are conceptually different.  The defining difference between the two is Inversion of Control.

A library is a collection of classes and functions that you call from your code.  When you call a library from your code, you are in control.  jQuery is a library.  You call its functions from your code.

In a framework, the control is inverted.  The framework calls your code and controls how your application is architected.  A good example of a framework is Drupal.  Via its hook system, it calls your custom code but flow control remains in Drupal.  You can find an excellent discussion of libraries vs. frameworks in Martin Fowler’s Inversion of Control article referenced at the bottom.

Backbone.js, ReactJS and Knockout are libraries.  AngularJS and Ember.js are frameworks.  Libraries are more customizable than frameworks.

What it can do

The best way to gain an understanding of what Backbone can do is to explore how it is being used on live sites from the examples section of the Backbone home page.  Most of the examples there are Single Page Applications but beware, many require you to register to explore their apps.

If you are code literate, reading the fully-commented version of the backbone.js source code is another good way to gain familiarity with how it works.

The major advantage to using a front end library like Backbone is that client side separation of data from display can enable faster, more responsive user interfaces and reduced server traffic.  It would be difficult to create a scalable, maintainable client-side application only using JavaScript and jQuery.

Why it is part of Drupal 8

The Drupal community decided that a JavaScript MVC allowing for advanced client side functionality should be included in Drupal Core. After a lengthy debate, Backbone was included in Drupal 8 because it was deemed the most stable front-end library with the largest community of users.  It is also lightweight (roughly 9k compressed) and interfaces well with Drupal.  Backbone models and collections map to Drupal entities and Views well.

Backbone Components

Backbone has 4 core components: Model, View, Collection and Router.

Models

Models are enhanced JavaScript objects.  They form the core of all Backbone data interactions.  Their most important function is to act as containers for structured data.  Since Backbone supports RESTful interfaces out of the box, Models can easily be synchronized with back-end data sources.

Created using a namespace coding technique to prevent variable name conflicts by extending Backbone.Model, models contain application data as well as logic and behavior.  They raise events when their state changes via the following methods:

  • initialize() - called when a new model instance is created.  This is also a good place to add event listeners.
  • get() - gets a property of the model
  • set() - adds or updates a property of a model
  • on() - triggers model changes

save() - if called on a model, it uses the model’s id and the collection’s URL to create a new model via HTTP POST update the model on the server via HTTP PUT.

destroy() - removes a model from its collection and uses the collection’s URL to delete the model on the server with HTTP DELETE.

The Backbone.Model object also has a validate() function that is called when save() or set() are fired.

Views

Views are a visual representation of models but do not contain HTML markup.  They contain the logic behind the model’s web page presentation.  Created by extending Backbone.View, views usually observe models and are notified when the underlying models change.  By displaying model data on the page, they tie the model and HTML page together by observing models and updating the user interface when changes occur.  Views are dependent on one another and can communicate with one another.  DOM events are handled by Views.

Since Views manage both the event handlers and DOM elements, they control all input and output on a Backbone-powered site.

el is short for element and can be thought of as the central property of a view because all views must have one.  It is essentially a reference to a DOM element.  $el is a corresponding jQuery element that contains the el property.

setElement can be used to apply an existing Backbone view to a different DOM element.  setElement will create a cached el reference for you and move the delegated events for a view from the old element to the new one.

render() renders model data as HTML on a web page using Underscore’s JavaScript templating engine.  If bound to the model’s change() event, the view can instantly reflect model changes without a page refresh.

There are several other functions available for managing views elements.

Controller - The controller acts as a bridge between the model and view.  It handles clicks and other user actions from the view, updates models and transports model data back to the view so it can handle the output (a model can have multiple views observing it).  As mentioned earlier, Backbone is not traditional MVC framework because it does not have a distinct Controller.  In Backbone, the Controller responsibility is merged into the View and performed by the template, not the Backbone.View.

Templates - Templates are rendered by Underscore.  For better performance templates should be pre-compiled.

  • <%...%> - execute arbitrary code
  • <%=...%> - evaluate an expression and render the result inline
  • <%-...%> - evaluate an expression and render the html escape result inline

Collections

Collections manage models.  They can be thought of as souped-up JavaScript arrays with extra functions added.  Collections are created by extending Backbone.Collection.

If you specify a comparator (either a custom method or by using one of Underscore’s sorting methods), Backbone will automatically sort all Models added to the collection.

Event listeners can added to collections to be triggered when models are added or removed from a collection.

set() - can perform add, remove, and change operations on a collection.

reset() - replaces all collection contents.

remove() - removes a model from the collection but not from the server.

fetch() - sends a GET request to the location in the collection’s url property to retrieve a JSON array of models.  After the models are received, set() is automatically executed to update the collection.  By default, it merges any new data from the server with any data already on the client.

create() - creates a new collection.

Routing

Routers are what Backbone and other frameworks use to simulate page changes.  They enable single page applications.  Using the router class and only one HTML file, you could create an entire site with an unlimited number of virtual pages.

Routes are set using key-value pairs where the key is the URL route and the value is the function that is called when a user navigates to that route.  HTTP requests are routed through a single entry point where they are analyzed by the Front Controller that invokes the method of the corresponding controller.

Each time a user browses a page, the router decides which Views to render and records the visit in the Backbone.history object that allows visitors to use the browser’s Back button to navigate Backbone applications.  Note that the history object does not replace the browser’s history.  It manages what gets added to the history and when.

Backbone allows you to choose from either the default hash-based (eg. www.mysite.com/foo#bar) routing or the HTML5 pushState approach that results in cleaner URLs but is not supported by older browsers.

Events

Events such as mouse clicks bind custom JavaScript events to code.  In Backbone, event code is mixed in with other Backbone components.  Backbone classes that include events are Backbone.Model, Backbone.View, Backbone.Router and several others.

Events are a key component of Backbone and any other front-end framework or model and, since they are mixed in with other components, mastering their usage is key to becoming productive with Backbone.

Sync

Sync maps Backbone data to the server and thereby handles all persistence.  Whenever Backbone tries to read, save or delete models, Backbone.sync is called.  Although sync uses jQuery’s $.ajax() to make RESTful requests, it can be overridden globally or by adding a sync function to a Backbone collection or model.

Backbone.sync is called with the following 3 parameters:

  1. method - read, create, update, delete, patch or delete
  2. model - the Backbone model object
  3. options - typically include success or error handling methods

Where Drupal 8 Uses Backbone

The only uses of Backbone I am aware of in Drupal core is its toolbar interaction handling and in-place editing.

My Conclusion

Backbone was chosen for inclusion by the Drupal community in 2011 but today it’s one of the older front end libraries in use.  Since then, several other front end libraries and frameworks have emerged.  While Backbone has proven itself in production and has a vibrant community of developers who have authored a wide array of extensions, libraries and testing tools, I would be more comfortable using an open source library with a company behind it like AngularJS or ReactJS.

Since Backbone is a library and not a framework, it can work with other front end libraries.  Unlike some of the front-end frameworks, Backbone doesn’t need to control the whole page.  It can be used on a small section of the page so a good use case for Backbone in Drupal might be for data-rich, in-page applications.

Resources

http://backbonejs.org/
https://github.com/addyosmani/backbone-fundamentals
https://www.drupal.org/node/1149866
http://martinfowler.com/bliki/InversionOfControl.html