Chicago Boss and Backbone.js

In this tutorial we are going to be using the Backbone.js Todo App with a Chicago Boss backend to power realtime updates.

* For this tutorial I am going to assume that you have git and erlang installed

** If you want to just grab the code you can grab it at or checkout the demo Just make sure to edit the with the correct paths

To get started lets grab a copy of Chicago boss and get everything built
$ git clone
$ cd ChicagoBoss
$ make get-deps && make deps && make

Now that we have the framework built we can get started with our application
$ make app PROJECT=todo

Grab Backbone.js
$ cd ..
$ git clone

Grab the destructure json library for erlang

$ git clone

We need to copy some of the files from the backbone example over to our application
$ mkdir todo/priv/static/js
$ mkdir todo/priv/static/css
$ cp backbone/backbone.js todo/priv/static/js/
$ cp backbone/examples/todos/todos.js todo/priv/static/js
$ cp backbone/examples/todos/todos.css todo/priv/static/css
$ cp backbone/examples/todos/destroy.png todo/priv/static/
$ mkdir todo/src/view/home
$ cp backbone/examples/todos/index.html todo/src/view/home/home.html
$ cp erlang_destructure_json/destructure_json.erl todo/src/lib
$ cp erlang_destructure_json/json.erl todo/src/lib

To get started add this line to the end of todo/priv/todo.routes
{"/", [{controller, "home"}, {action, "home"}]}.

Then edit todo/priv/static/css/todos.css to link to the destory image correctly (line 150)
background: url(/static/destroy.png) no-repeat 0 0;

Now edit todo/src/view/home/home.html update the script tags with these
<link href="/static/css/todos.css" media="all" rel="stylesheet" type="text/css"/>
<script src=""></script>
<script src=""></script>
<script src=""></script>
<script src="/static/js/backbone.js"></script>
<script src="/static/js/todos.js"></script>
<script type="text/javascript">
var timestamp = {{ timestamp }};

And lets create the home controller todo/src/controller/todo_home_controller.erl
-module(todo_home_controller, [Req, SessionId]).

home(‘GET’, []) ->
Timestamp = boss_mq:now(“updates”),
{ok, [{timestamp, Timestamp}]}.

In the home function we are grabbing the timestamp for the updates queue and pass that to the view so that we know the time to pass when we start polling for updates. Create the todo model todo/src/model/todo.erl
-module(todo, [Id, Text, Order, Done]).

after_create() ->
boss_mq:push(“updates”, THIS).

after_update() ->
boss_mq:push(“updates”, THIS).

This is just a simple model that on save and update pushes that information to the boss_mq Now lets create the controller to handle the polling todo/src/controller/todo_poll_controller.erl
-module(todo_poll_controller, [Req, SessionId]).

getUpdate(‘GET’, [LastTimestamp]) ->
{ok, Timestamp, Objects} = boss_mq:pull(“updates”, list_to_integer(LastTimestamp)),
{json, [{timestamp, Timestamp}, {objects, Objects}]}.

Here we just have one action that waits for something to be pushed to the message, when it gets a new object it returns it along with the timestamp. Now lets create the restful controller to handle the todos todo/src/controller/todo_todos_controller.erl
-module(todo_todos_controller, [Req, SessionId]).

index(‘GET’, []) ->
%% Get all of the todos and output a json list of them
Todos = boss_db:find(todo,[]),
{json, Todos};

index(‘POST’, []) ->
%% create a new Todo
Json = mochijson2:decode(general_lib:to_list(Req:request_body())),
Todo = boss_record:new(todo, [
{id, id},
{text, json:destructure(“Obj.text”, Json)},
{order, json:destructure(“Obj.order”, Json)},
{done, json:destructure(“Obj.done”, Json)}
case Todo:save() of
{ok, SavedTodo} ->
{json, SavedTodo};
{error, Error} ->
{json, [{error, Error}]}

index(‘PUT’, [Id]) ->
%% Update an existing todo
Json = mochijson2:decode(general_lib:to_list(Req:request_body())),
Todo = boss_db:find(Id),
UpdatedTodo = Todo:set([
{text, json:destructure(“Obj.text”, Json)},
{order, json:destructure(“Obj.order”, Json)},
{done, json:destructure(“Obj.done”, Json)}
case UpdatedTodo:save() of
{ok, SavedTodo} ->
{json, SavedTodo};
{error, Error} ->
{json, [{error, Error}]}

index(‘DELETE’, [Id]) ->
%% Delete this todo
Todo = boss_db:find(Id),
{json, Todo}.

This is just a standard rest interface to the todos. Finally lets make a few changes to todo/priv/static/js/todos.js
// An example Backbone application contributed by
// [Jérôme Gravel-Niquet]( This demo uses a simple
// [LocalStorage adapter](backbone-localstorage.html)
// to persist Backbone models within your browser.

// Load the application once the DOM is ready, using `jQuery.ready`:

// Todo Model
// ———-

// Our basic **Todo** model has `text`, `order`, and `done` attributes.
window.Todo = Backbone.Model.extend({

// Default attributes for a todo item.
defaults: function() {
return {
done: false,
order: Todos.nextOrder()

// Toggle the `done` state of this todo item.
toggle: function() {{done: !this.get(“done”)});

url : function() {
return ? ‘/todos/index/’ + : ‘/todos’;


// Todo Collection
// —————

// The collection of todos is backed by *localStorage* instead of a remote
// server.
window.TodoList = Backbone.Collection.extend({

// Reference to this collection’s model.
model: Todo,

// Save all of the todo items under the `”todos”` namespace.
// localStorage: new Store(“todos”),
url :’/todos/index’,

// Filter down the list of all todo items that are finished.
done: function() {
return this.filter(function(todo){ return todo.get(‘done’); });

// Filter down the list to only todo items that are still not finished.
remaining: function() {
return this.without.apply(this, this.done());

// We keep the Todos in sequential order, despite being saved by unordered
// GUID in the database. This generates the next order number for new items.
nextOrder: function() {
if (!this.length) return 1;
return this.last().get(‘order’) + 1;

// Todos are sorted by their original insertion order.
comparator: function(todo) {
return todo.get(‘order’);


// Create our global collection of **Todos**.
window.Todos = new TodoList;

// Todo Item View
// ————–

// The DOM element for a todo item…
window.TodoView = Backbone.View.extend({

//… is a list tag.
tagName: “li”,

// Cache the template function for a single item.
template: _.template($(‘#item-template’).html()),

// The DOM events specific to an item.
events: {
“click .check” : “toggleDone”,
“dblclick div.todo-text” : “edit”,
“click span.todo-destroy” : “clear”,
“keypress .todo-input” : “updateOnEnter”

// The TodoView listens for changes to its model, re-rendering.
initialize: function() {
this.model.bind(‘change’, this.render, this);
this.model.bind(‘destroy’, this.remove, this);

// Re-render the contents of the todo item.
render: function() {
return this;

// To avoid XSS (not that it would be harmful in this particular app),
// we use `jQuery.text` to set the contents of the todo item.
setText: function() {
var text = this.model.get(‘text’);
this.input = this.$(‘.todo-input’);
this.input.bind(‘blur’, _.bind(this.close, this)).val(text);

// Toggle the `”done”` state of the model.
toggleDone: function() {

// Switch this view into `”editing”` mode, displaying the input field.
edit: function() {

// Close the `”editing”` mode, saving changes to the todo.
close: function() {{text: this.input.val()});

// If you hit `enter`, we’re through editing the item.
updateOnEnter: function(e) {
if (e.keyCode == 13) this.close();

// Remove this view from the DOM.
remove: function() {

// Remove the item, destroy the model.
clear: function() {


// The Application
// —————

// Our overall **AppView** is the top-level piece of UI.
window.AppView = Backbone.View.extend({

// Instead of generating a new element, bind to the existing skeleton of
// the App already present in the HTML.
el: $(“#todoapp”),

// Our template for the line of statistics at the bottom of the app.
statsTemplate: _.template($(‘#stats-template’).html()),

// Delegated events for creating new items, and clearing completed ones.
events: {
“keypress #new-todo”: “createOnEnter”,
“keyup #new-todo”: “showTooltip”,
“click .todo-clear a”: “clearCompleted”

// At initialization we bind to the relevant events on the `Todos`
// collection, when items are added or changed. Kick things off by
// loading any preexisting todos that might be saved in *localStorage*.
initialize: function() {
this.input = this.$(“#new-todo”);

Todos.bind(‘add’, this.addOne, this);
Todos.bind(‘reset’, this.addAll, this);
Todos.bind(‘all’, this.render, this);


// Re-rendering the App just means refreshing the statistics — the rest
// of the app doesn’t change.
render: function() {
total: Todos.length,
done: Todos.done().length,
remaining: Todos.remaining().length

// Add a single todo item to the list by creating a view for it, and
// appending its element to the `



      addOne: function(todo) {


      var view = new TodoView({model: todo});





// Add all items in the **Todos** collection at once.
addAll: function() {

// If you hit return in the main input field, and there is text to save,
// create new **Todo** model persisting it to *localStorage*.
createOnEnter: function(e) {
var text = this.input.val();
if (!text || e.keyCode != 13) return;
Todos.create({text: text});

// Clear all done todo items, destroying their models.
clearCompleted: function() {
_.each(Todos.done(), function(todo){ todo.destroy(); });
return false;

// Lazily show the tooltip that tells you to press `enter` to save
// a new todo item, after one second.
showTooltip: function(e) {
var tooltip = this.$(“.ui-tooltip-top”);
var val = this.input.val();
if (this.tooltipTimeout) clearTimeout(this.tooltipTimeout);
if (val == ” || val == this.input.attr(‘placeholder’)) return;
var show = function(){; };
this.tooltipTimeout = _.delay(show, 1000);


function waitForMsg(currentTime){
/* This requests the url “msgsrv.php”
When it complete (or errors)*/
type: “GET”,
url: “/poll/getUpdate/” + currentTime,

async: true, /* If set to non-async, browser shows page as “Loading..”*/
//cache: false,
timeout:5000000, /* Timeout in ms */

success: function(data){
for (var i = 0; i < data.objects.length; i++){
var t = new Todo({
id: data.objects[i].id,
text: data.objects[i].text,
done: data.objects[i].done,
order: data.objects[i].order
if(typeof(Todos.get( != “object”){
} else {
var r = Todos.get(;
r.set({text:data.objects[i].text, done:data.objects[i].done, order:data.objects[i].order});
}, 500);
error: function(XMLHttpRequest, textStatus, errorThrown){
console.log(“error ” + textStatus + ” (” + errorThrown + “)”);
// waitForMsg(), /* Try again after.. */
// “15000”); /* milliseconds (15seconds) */

window.App = new AppView;


You should be ready to start the app now 🙂 ** Right now there is a problem with the destructure_json stuff and it will fail if you dont make the project before running I am looking into this, but for now just run make 🙂

$ cd todo
$ make
$ ./

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: