I’m finally using Backbone.js. It’s brilliant and I can’t recommend it enough. Backbone is not trivial but it solves a difficult problem.
So I needed a modal dialog. I messed about with a couple of modal dialog plugins but had problems getting them to work in a way that fits in with Backbone.js. After finding out how easy it is to create your own modal dialogs I decided to create a new Backbone.js view from which other views can derive and inherit modal functionality.
You can download a demo of my Backbone modal view from my Github page which looks like this :
The demo doubles as a basic demonstration of Backbone.js and of my modal view. When you click “Add another person to the list” a Backbone view is created which derives from ModalView. This gives the child Backbone view a showModal() method. You just render your view as normal and then call showModal(). For example here is the click handler for the add person button :
$("#addPersonButton").click(
function( event)
{
// Create the modal view
var view = new AddPersonView();
view.render().showModal(
{
x: event.pageX,
y: event.pageY
});
});
The AddPersonView class extends my ModalView class like this :
AddPersonView = ModalView.extend(
{
name: "AddPersonView",
model: PersonModel,
templateHtml:
"<form>" +
"<label for="personName">Person's name</label>" +
"<input id="personName" type="text" />" +
"<input id="addPersonButton" type="submit" value="Add person" />" +
"</form>",
initialize:
function()
{
_.bindAll( this, "render");
this.template = _.template( this.templateHtml);
},
events:
{
"submit form": "addPerson"
},
addPerson:
function()
{
this.hideModal();
_people.add( new PersonModel({name: $("#personName").val()}));
},
render:
function()
{
$(this.el).html( this.template());
return this;
}
});
Because AddPersonView extends ModalView you can call showModal() on your view and this happens :
What you’re seeing is the el property of the AddPersonView instance being rendered into a modal container which gives you a few things for free :
- You can close the dialog by either pressing escape, clicking outside of the dialog or pressing the close icon
- The background is shaded back to highlight the modal view
- The focus is automatically set on the first form control in the modal view
- The modal dialog is, by default, positioned in the centre of the screen
In this example I’m positioning the dialog at the mouse cursor coordinates at the point when you click the “Add another person to the list” button. You can pass an options object to showModal() which gives you a bit of control of the internals of the modal dialog code. Here are the defaults that you can override :
defaultOptions:
{
fadeInDuration:150,
fadeOutDuration:150,
showCloseButton:true,
bodyOverflowHidden:false,
closeImageUrl: "close-modal.png",
closeImageHoverUrl: "close-modal-hover.png",
}
And as you have seen you can also pass in x and y properties. Hopefully these options are self explanatory except perhaps bodyOverflowHidden which helps the dialog stay on screen. The new Twitter add new tweet dialog does something like this too.
The demo includes two images that represent the close button and its hover state (it goes red when you hover over it). You can override the images easily through the showModal() parameter.
Back to the demo
If you type a name in and press the Add person button then a person model is added to the person collection. Because this is Backbone.js this automatically triggers the rendering of a new PersonItemView into the PersonListView :
I’m Happy
I’m happy I stepped back and learned javascript properly and got into Backbone.js. I find that being self critical and determined makes you a better developer. Backbone.js forces you to break your UI down into small units and collections of units, each with their own set of event handlers. And it forces you to do this before you start creating your UI. This is crucial because it enforces design and forethought, the absence of which normally leads to big balls of code mud.
To learn Backbone.js I found the following resources useful :
- Joey Beninghove’s Backbone.js Quickly screencast
- PeepCodes Backbone.js Basics and Backbone.js Interactivity screencasts
- Tekpub’s Backbone.js APS.NET MVC 3 screencast
- Chris Strom’s stream of Backbone.js consciousness
- Nik Gauthier and Chris Strom’s Recipes With Backbone book
- The top quality Backbone.js documentaion
- Rob Conery’s blog posts where he refactored the ToDo list demo
Finally I know that modal dialogs are known to be not in the best interests of usability but there is a subtle difference between true I-want-to-take-over-your-app-and-secretly-own-the-whole-world modal dialogs and these soft easily-closed dialogs. Facebook uses soft dialogs, as does Twitter. Use inline editing where it makes sense and a separate page where a modal dialog is being asked to do too much.
Download the code and demo from github or see the demo page live in action
Update: v0.3 is complete adding a few new features I needed.




Nice to see an article of how a widget would be created in Backbone. I was thinking along the same lines myself. You could even bundle this up to use in an app that doesn’t use Backbone. Firstt paragraph in “I’m Happy” is a good argument to devs not using something like backbone to build apps.
perfect, thanks!
Is it possible to use this as a confirmation dialog for a different view?
ModalView integrates very nicely into the app as a self-contained model but what I’m trying to achieve is the following:
1. Have a view that defines a list of items and knows how to initiate removal of one:
var FilesystemView = Backbone.View.extend({
// ... this view has its own element and renders it
events: {
"click .fs-remove": "triggerRemove"
}
triggerRemove: function() {
var confDialog = new RemoveFSConfView(); // this is an instance of ModalView
confDialog.render().showModal();
},
handleRemove: function() {
// instruct the backend server to actually remove the file system
}
});
2. The modal dialog works all great and triggers the ‘handleRemove’ method; however, the ‘handleRemove’ method does not have the context any more that the ‘triggerRemove’ method did following user’s click event.
So, is there a pattern I should use in how to setup the views so that the ModalView can be used? I don’t think I can just make the FilesystemView inherit from the ModalView because it has its own el that it handles so that would require changes to the ModalView to be able to take an arbitrary el, right?
Overall, really cool widget and if you can give me any pointers for the this use case, I’d appreciate it. Thanks!
Ok I think I know what you are trying to do. In your FilesystemView initialise() function you could call :
this.handleRemove = _.bind( this.handleRemove, this);
This replaces the function with a wrapper function that passes in the context you need. I presume you setup an event somewhere in RemoveFSConfView that the FilesystemView handles? If this is way off let me know I just need to know exactly what you are doing.