Create reactive data UIs with Backbone.js
Matt Dennewitz explains how to build a simple UI and set it to update periodically with streamed information, using Backbone.js.
Between Backbone.js, AngularJS, Ember.js, React and all the rest, developers are not at a loss for high-quality JavaScript libraries to power user interfaces. Each library offers roughly the same core set of features: dynamic interaction between data and visual representation, organisation of that data by means of stores and discrete models, and maintenance of a browser state.
However, unlike libraries such as AngularJS and Ember.js, Backbone.js is designed around an adaptable set of 'views' (which encapsulate logic behind independent data-bound elements), 'models' (structured units of data and context-specific logic) and 'collections' (typically with an API to load, filter and otherwise manipulate sets of data units). On top of that, it offers event dispatching, client-side URL manipulation and history management.
At Pitchfork, our approach is often to create the skeletal structure of an interface in HTML, and then terraform it with Backbone. To give a brief sense of Backbone's lightness and power, let's use this strategy to design a simple interface that reflects the current value from a periodically updated data stream – a ticking clock. This will illustrate how straightforward modelling a reactive UI can be, using the tools Backbone provides.
Getting started
To start, let's bootstrap our application with Backbone, Underscore (a functional programming library and Backbone's only hard requirement) and jQuery. These libraries should be loaded in the <head> of our document. Let's assume that they live in a folder named 'js' at the same level as our page, index.html. Here, we'll also include the source of our application, app.js – place all JavaScript inside this file. Inside <body> is an empty <div> element that we'll bind to our clock.
<!doctype html>
<html>
<head>
<!-- libraries -->
<script src="js/jquery.js"></script>
<script src="js/underscore.js"></script>
<script src="js/backbone.js"></script>
<!-- our application -->
<script src="js/app.js"></script>
</head>
<body>
<div id="current-time"></div>
</body>
</html>
This is the whole of our interface. We've loaded the necessary libraries and designed the skeleton of our UI. Now we'll wrap the interface with Backbone.
Designing our application
Consider for a moment the three moving parts in this application: a dispatcher, a data stream and a view. Let's break them down.
Broadcasting changes is critical to a data-reactive app. Because any number of UI elements might need to take action based on changes in a data stream, we have much to gain from centralising communication into a single point, called a dispatcher. Backbone.Events provides a way for interested parties – views, collections and so on – to subscribe to and publish events and relative data.
Subscribers tell the dispatcher that they're interested in responding to a certain event by providing a function, called a callback, meant to handle that event. Publishers broadcast information by triggering specific events with new or relevant data. Essentially, the dispatcher is what synchronises communication between decoupled moving parts. In our example, it ties together the ticking clock and the clock's display.
Let's create a dispatcher, and name an event to communicate.
var newDataFlag = 'data-arrived';
var Dispatcher = _.extend({}, Backbone.Events);
Next, we'll need a mechanism that acts as a live data stream. In practice this could be a WebSocket or an Ajax function, or anything that produces data. For our purposes, we'll create a ticking clock with setInterval. Every second, we'll dispatch the current time via the data-arrived event. When the dispatcher triggers data-arrived, anyone listening will receive the current time.
setInterval(function() {
var currentTime = (new Date()).toLocaleTimeString();
Dispatcher.trigger(newDataFlag, currentTime);
}, 1000);
Finally, we'll need a Backbone view to wrap our UI element, listen for updated data from the dispatcher and reflect new data in the UI. To create a view, we'll extend Backbone.View with our logic. Our view, which we'll name CurrentTimeView, will wrap the #current-time UI element, which we'll specify later, at creation time. It is the glue between the data stream and the UI. We'll add two methods: instantiate – the view's constructor, and render, which updates the view's DOM element with the current time.
When a view is instantiated, its initialize method is called. Basic setup work can be done here, such as binding to click or key events, or rendering the view itself. Our view needs to do two things when it comes to life. First, it needs to share the view's state with a render method by 'binding' it to the view. Second, it needs to subscribe to dispatcher updates.
In subscribing, the view specifies that its render method should be called when the data-arrived event is triggered by the dispatcher. When called, this view's render method receives the current time and updates the underlying DOM element that we'll give it when instantiating.
This is what our view looks like:
var CurrentTimeView = Backbone.View.extend({
initialize: function() {
// bind "render" to this view with Underscore's "bindAll"
_(this).bindAll('render');
// render this view when new data is broadcast
Dispatcher.on(newDataFlag, this.render);
},
render: function(currentTime) {
// set our DOM element's text content to the clock's current time
this.el.textContent = currentTime;
}
});
Notice this.el in render? Backbone views expose their underlying DOM elements in two ways: this.el, the actual DOM node, and this.$el, a jQuery object around the element. While unnecessary for simply updating an element's text, the convenience of this.$el should not go un-noted.
And that's it! We've designed a data stream that pumps out data, an emitter that keeps any number of subscribers in sync with data updates, and a view that connects the data to the interface. All that's left now is to boot the application on page load. To boot, we simply instantiate the CurrentTimeView, specifying the element to wrap.
$(function() {
new CurrentTimeView({
el: document.getElementById('current-time')
});
});
The results are visible at once. Backbone has allowed us to sketch a simple UI, wrap it with interactivity and lay the foundation for synchronising information from a stream, through one or many components. Imagine replacing this simple example with something more powerful. You can see how little code it takes to develop a meaningful data-driven application with Backbone.
Words: Matt Dennewitz
Matt Dennewitz is vice president of product at Pitchfork. This article originally appeared in issue 267 of net magazine.
Liked this? Read these!
- The ultimate guide to logo design
- Useful and inspiring flyer templates
- Download free textures: high resolution and ready to use now
Thank you for reading 5 articles this month* Join now for unlimited access
Enjoy your first month for just £1 / $1 / €1
*Read 5 free articles per month without a subscription
Join now for unlimited access
Try first month for just £1 / $1 / €1
Get top Black Friday deals sent straight to your inbox: Sign up now!
We curate the best offers on creative kit and give our expert recommendations to save you time this Black Friday. Upgrade your setup for less with Creative Bloq.
The Creative Bloq team is made up of a group of design fans, and has changed and evolved since Creative Bloq began back in 2012. The current website team consists of eight full-time members of staff: Editor Georgia Coggan, Deputy Editor Rosie Hilder, Ecommerce Editor Beren Neale, Senior News Editor Daniel Piper, Editor, Digital Art and 3D Ian Dean, Tech Reviews Editor Erlingur Einarsson and Ecommerce Writer Beth Nicholls and Staff Writer Natalie Fear, as well as a roster of freelancers from around the world. The 3D World and ImagineFX magazine teams also pitch in, ensuring that content from 3D World and ImagineFX is represented on Creative Bloq.