The web development world is changing. Standards such as HTML5, ECMAScript and CSS3 are helping to design more responsive and interactive web applications. Graphics, multimedia and device interactions are first class citizens in web applications and you don’t have to use plugins to create sophisticated features. These changes help web developers to build next generation rich internet applications (RIAs).
In the past few years, we have also seen an emerging trend to build Single Page Applications (SPAs). SPAs are web applications that include only one HTML page that acts as a shell to the whole application. This shell is changed via JavaScript interactions made by the users, client-side template engines and client-side routing mechanisms. That means you can create RIAs using HTML, CSS and JavaScript and gain a lot of smart client qualities, such as being stateful and responsive.
One recommended way to create SPAs is by using libraries or frameworks that expose features such as routing, template engines and ways to communicate with the server. The popular SPA frameworks are AngularJS and Ember. One of the popular libraries that help to create SPAs is Backbone.js. In this article we will take a look at Backbone.js and how you can use some of its features. While we won’t cover the ways Backbone.js can help you create SPAs, you can find more content about it in “Pro Single Page Application Development” (Apress) book or by searching online.
What is Backbone.js?
Backbone.js is a Model-View-Whatever (MVW) library that was written by Jeremy Ashkenas, the creator of CoffeeScript and Underscore.js. Backbone.js is a lightweight JavaScript library that enforces developers to organize their code in a clean and efficient manner and eases the development of SPAs. In its core, Backbone.js includes five main objects that the developer can extend with his/her own functionality:
- Models – data structure wrappers
- Collections – sets of models
- Views – the code behind a HTML view
- Routers – expose client-side routing mechanism
- Events – enables to extend any object with event handlers
Each of the objects comes with its own APIs which enables many common development tasks. You can learn more about each of the objects in Backbone.js website: http://backbonejs.org.
Backbone.js also includes an API called sync API that is exposed by Backbone.sync function. This API enables communication with the server, and the model and collection objects use it underneath to synchronize their data when you use their create/update/delete APIs. The sync API is out of scope for this article. Now that you know what Backbone.js offers, we can take a dive into Backbone components.
Setting up the Environment for Backbone.js
Before you start working with Backbone.js, you should download its latest version and also download Underscore.js and jQuery. The reason that you will need Underscore.js is that Backbone.js has a dependency on the library and it uses many of Underscore.js utility functions underneath. Backbone.js also depends on jQuery when you extend its View object or when you use its Router object; so don’t forget to download it as well.
You can download the libraries using the following links:
Now that you have downloaded the libraries, you can create a small HTML file and add a script reference to all the files. The following code example is a template for that HTML web page:
Webpage Title
Once you have all the libraries in place, let’s start by explaining the first Backbone.js object – the Model.
The Model
The Model in Backbone.js is just a data structure that acts as a model in the application. The Model responsibility is to store data and expose functionality to manipulate it. If you want to create a Model object, you will first want to create its definition. The following code example shows how to define a Model called Customer using Backbone.js API:
var Customer = Backbone.Model.extend({
defaults: {
name: "",
type: "Regular"
}
});
As you can see in the code example, you just need to extend the Backbone.js Model object. In the example, you can see that if a Model is initialized without attributes, it will get the defaults set by the option object that was passed to the Backbone.Model.extend function.
There is a variety of useful model APIs such as getters, setters, events or the initialize function. The following code example will show you how to use some of those API functions:
var Customer = Backbone.Model.extend({
defaults: {
name: "",
type: "Regular"
},
initialize: function(){
console.log(‘model is initialized’); // This sentence is printed to the console every time the model is initialized
}
});
var customer = new Customer(); // initialize function is called here
console.log(customer.get(‘type’)); // no type is written to the console
customer.set(‘type’, ‘Platinum’);
console.log(customer.get(‘type’)); // Platinum is written to the console
The code is really self-explanatory and very simple to understand by reading the comments added to the code. Now that you know what the Model object is, it is time to learn about another Backbone.js object – the Collection.
The Collection
In Backbone.js, a Collection is a data structure that holds zero to infinite number of Model instances. Like Models, you will define a Collection by extending the Collection Backbone.js object. The following code example shows how to create a Collection to the Customer model you saw in the “The Model” section:
var Customers = Backbone.Collection.extend({
model: Customer
});
Once you define a Collection, you can start using its instances as sets of Model instances. Collections expose API functionality that you can use to manipulate them. For example, you can add or remove Models using the add and remove functions or you can retrieve Models by their ‘id’ using the get function. The entire collection API is beyond the scope of this article, but can always look it up in the Backbone documentation at http://backbonejs.org/#Collection . Collections also expose many of the Underscore.js array utility functions. You can use forEach, sortBy or filter functions to iterate, sort or filter your collections. This is why Backbone.js has a hard dependency on Underscore.js. The following code shows some of these functions in action:
var Customers = Backbone.Collection.extend({
model: Customer
});
// initialize two customer objects
var dave = new Customer({
name: "Dave"
});
var jane = new Customer({
name: "Jane",
type: "Platinum"
});
// initialize a collection with the previous customer objects
var customers = new Customers([ dave, jane ]);
// sort the customers by their type and print them to the console
var sortedByType = customers.sortBy(function (customer) {
return customer.get(‘type’);
});
customers.forEach(function(customer) {
console.log(customer.get(‘type’));
});
Now that you are familiar with Backbone.js Models and Collections, we can move on to the next Backbone.js object that we will explore in this article – the View.
The View
The View object in Backbone.js is responsible for displaying the model data inside of an HTML structure. . You can divide your entire web page into small HTML pieces which interact with their own view object and construct a full view. The following code example shows how to define a View object by extending Backbone.js View object:
var CustomerView = Backbone.View.extend({
// view configuration
});
The view itself uses a template that is rendered by the View logic. In Backbone.js, you use the Underscore.js template engine to create your Views. For example, for a customer view, you might want to use a template such as the following:
When this template is rendered, the output will be the customer’s name and type, in two different DIVs.
The article doesn’t cover the syntax of Underscore.js templates but a good starting point to understand it is the following link: http://underscorejs.org/#template.
In order to compile a template using Underscore.js, you will use the template function:
var compiledTmpl = _.template($("#customer-template").html());
Once you have a compiled template, you can use it as the template for the View and bind it to a Model.
In a View, there are two properties which are very crucial to understand: el and $el. The el property is the HTML element that is bound to the View. The $el property is a jQuery object that wraps the el element and exposes jQuery functions that you can use. The next code example shows how to bind a customer View to an element with a customer id and how to use template engine to compile a template:
var CustomerView = Backbone.View.extend({
el: "#customer",
template: _.template($("#customer-template").html())
});
In order to render a View, you will need to define a render function inside the view options object. The render function will use the view element, template and model to create the visualization of the View. The following code example shows how to do that:
var CustomerView = Backbone.View.extend({
el: "#customer",
template: _.template($("#customer-template").html()),
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
In the previous example, you can see the use of the model’s toJSON function to get the model’s attributes from the Model. The Model is passed to the compiled template to create binding between both of them. Next, the $el’s HTML is set to the output of the binding. One last thing to notice in the render function is the return statement that returns the View itself. You should always return the View from the render function in order to make it chainable.
Views can also react to events and handle them. Backbone.js View includes an events attribute that you can pass in the options objects when you extend the View object. The events attribute is a JavaScript literal object where each of its attribute name indicates the event, and the selector of the element, that triggers the event. The value of the attribute will be the name of the function that will be triggered by the event. The following example shows you how to wire a click event to an element with myEvent id in the Customer view (it doesn’t exists in the template you previously saw) and wire it to a doSomething function:
var CustomerView = Backbone.View.extend({
el: "#customer",
events: {
"click #myEvent": "doSomething"
},
template: _.template($("#customer-template").html()),
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
doSomething: function() {
console.log("did something");
}
});
There are other aspects of views that this article doesn’t cover. For further information, I recommend going to Backbone.js website: http://backbonejs.org.
The Router
Routing is the most important mechanism in a SPA. In a SPA, you use client-side routing to change views in the SPA shell. Backbone.js includes a Router object that exposes routing using the # sign in the URL and HTML5 History API to keep track of the routing. When navigation occurs with the # sign in the URL, the Backbone.js Router will intercept the navigation and replace it with calls to route functions, that the developer provided.
When you want to use the Router, you will extend it like all the other Backbone.js objects. The following code shows a simple router:
var router = Backbone.Router.extend({
routes: {
"": "index",
"contact": "contact"
},
index: function() {
console.log("index route was triggered");
},
contact: function() {
console.log("contact route was triggered");
}
});
In the example, you can see the use of the routes literal object to configure all the routes and all the routing functions. When no route is supplied (for example http://myexample.com/#), the index function will be triggered. When someone uses the URL with # followed by contact (for example http://myexample.com/#contact), the contact function will be triggered. The Router object includes many other aspects such as API and custom routes, that won’t be covered in the article, but you can always refer the documentation to learn more.
The Events API
The Backbone.js Events API is an inner Backbone.js module that all the other Backbone.js objects use for event handling. The API offers functions such as on, off and trigger that resemble jQuery event model and can help you to wire event handlers to objects. Backbone.js also adds functions like listenTo and stopListening to enable an object to listen to events, on another object. We won’t cover how to use this API but in the example that we covered in The View section; when you used the events literal object, Backbone.js attached the event handler using the Events API.
Making Backbone.js Objects Work Together
Up till now, you only saw how different Backbone.js objects are defined. Let’s take a look at a small example of how to combine the objects in order to render some views. In the example, we are going to use two different templates; one for a customer object and one for customer list:
Once you put this HTML in your web page, add the following code which defines all the Backbone.js objects and runs the render functions of the views:
var Customer = Backbone.Model.extend({
defaults: {
name: "",
type: "Regular"
}
});
var Customers = Backbone.Collection.extend({
model: Customer
});
var CustomerView = Backbone.View.extend({
el: "#customer",
template: _.template($("#customer-template").html()),
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var CustomersView = Backbone.View.extend({
el: "#customers",
template: _.template($("#customers-template").html()),
events: {
"click li": "changeModel"
},
render: function () {
this.model.each(this.addOne, this);
return this;
},
addOne: function(car) {
this.$el.append(this.template(car.toJSON()));
},
changeModel: function(e) {
var customersArr = this.model.where({ "name": e.currentTarget.innerText
});
var customerView = new CustomerView({ model: customersArr[0] });
customerView.render();
}
});
// create two customers
var dave = new Customer({
name: "Dave"
});
var jane = new Customer({
name: "Jane",
type: "Platinum"
});
// create the customer collection
var customers = new Customers([dave, jane]);
// create the customers view and bind it to the customer collection
var customersView = new CustomersView({model: customers});
// render the customers view
customersView.render();
The code is very easy to understand. You define the objects you are going to use by extending Backbone.js objects. Later on, you just bind the Collection to the customers view and render that View. You can also see the Event Handler to change the Model while clicking on each list item in the list. When a list item is clicked, a customer view is created and shows the details of the customer. You can use online JavaScript playground websites such as jsFiddle to run this code and see it in action. The output might look like the following figure:
Figure: The Output of Running the Backbone.js application
Backbone.js in Real-World Examples
If you are still in two minds about using Backbone.js, just take a look at the list of websites and web applications that use it at: http://backbonejs.org/#examples. You will find that the list comprises of well known websites like USA Today, Airbnb and Khan Academy. You will also find web applications such as Foursquare, Bitbucket and Code School that make use of Backbone.
Summary
Backbone.js is a popular library that helps to impose structure in JavaScript. It also includes features that enables web developers to create SPAs more easily. You can use the exposed Backbone.js objects and their APIs to build common web functionality such as server interaction or DOM manipulation. Above all, Backbone.js has a huge community (~18500 stars and ~4100 forks in Github as of this writing).You can also find many Backbone.js plugins created by the community such as Backbone.Marionette and Knockback which can help you boost your development.
On the other hand, Backbone.js is only a library and you will need to use other libraries in order to create a lot of features that aren’t exposed by the library. If you like a much more complete SPA framework that imposes conventions, you might want to take a look at AngularJS or Ember. All in all, Backbone.js is very helpful and is used in a lot of known web applications and websites
Demo: You can find the code that was used in this section in jsFiddle website: jsfiddle.net/dotnetcurry/hbs4tLnf/
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Gil Fink is a web development expert, ASP.Net/IIS Micrsoft MVP and the founder of sparXys. He conducts lectures and workshops for individuals and enterprises who want to specialize in infrastructure and web development. He is also co-author of several Microsoft Official Courses (MOCs) and training kits, co-author of “Pro Single Page Application Development” book (Apress) and the founder of Front-End.IL Meetup. You can get more information about Gil in his website
gilfink.net