I'm currently working on a large web app built on backbone.js and have been having a lot of issues with organization, "zombies," etc. so I've decided to do a major refactor of code. I've already written a bunch of helper functions for dealing with the "zombies"; however, I'd like to start from the very beginning and create a nice structure/organization to the code. I haven't found many great tutorials/examples on large-scale backbone.js organization so I've sort of started from scratch and would like to see if I can get some opinions on where I've begun.
I've obviously set up my code within a global namespace; but I'd also like to keep that namespace rather clean. My main app.js keeps the class files themselves separate from the global namespace; you can register a class (so that it can be instantiated) by using the reg() function and the inst() function instantiates a class from the classes array. Thus, besides the 3 methods, the MyApp namespace only has Router, Model and View:
var MyApp = (function () {
var classes = {
Routers: {},
Collections: {},
Models: {},
Views: {}
};
methods = {
init: function () {
MyApp.Router = MyApp.inst('Routers', 'App');
MyApp.Model = MyApp.inst('Models', 'App');
MyApp.View = MyApp.inst('Views', 'App');
Backbone.history.start();
},
reg: function (type, name, C) {
classes[type][name] = C;
},
inst: function (type, C, attrs) {
return new classes[type][C](attrs || {});
}
};
return methods;
}());
$(MyApp.init);
Within the Models, Collections, Routers and Views, I work as usual but then need to register that class at the end of the file so that it could be instantiated at a later point (without cluttering the namespace) with:
MyApp.reg('Models', 'App', Model);
Does this seem like an unnecessary way to organize code? Do others have better examples of how to organize really large projects with many Routers, Collections, Models and Views?
I recently worked on a Backbone project called GapVis (code here, rendered content here). I don't know if it's "really large", but it's big-ish and relatively complex - 24 view classes, 5 routers, etc. It might be worth taking a look, though I don't know that all my approaches will be relevant. You can see some of my thinking in the long intro comment in my main app.js file. A few key architectural choices:
I have a singleton State
model that holds all current state info - the current view, what model ids we're looking at, etc. Every view that needs to modify application state does it by setting attributes on the State
, and every view that needs to respond to the state listens to that model for events. This is even true for views that modify state and update - the UI event handlers in events
never re-render the view, this is done instead through binding render functions to the state. This pattern really helped to keep views separate from each other - views never call a method on another view.
My routers are treated like specialized views - they respond to UI events (i.e. typing in a URL) by updating the state, and they respond to state changes by updating the UI (i.e. changing the URL).
I do several things similar to what you're proposing. My namespace has an init
function similar to yours, and a settings
object for constants. But I put most of the model and view classes in the namespace as well, because I needed to refer to them in multiple files.
I use a registration system for my routers, and considered one for my views, as a nice way to keep the "master" classes (AppRouter
and AppView
) from having to be aware of every view. In the AppView
case, though, it turned out that order of child views was important, so I ended up hard-coding those classes.
I'd hardly say that this was the "right" way to do things, but it worked for me. I hope that's helpful - I also had trouble finding visible-source examples of large projects using Backbone, and had to work out most of this as I went along.