Generally there's going to be a fairly specific load sequence you'll want to go through before you're ready to "respond" to the specific URL in your client code.
Typically, that sequence goes something like this:
<body>
tag.Now in code:
module.exports = {
// The main launch function. This is the
// entry point into your application.
launch: function () {
// Explicitly create a global called "app."
// Doing this first means it *always* exists
// if we need to access it from a view.
window.app = this;
// Attach some model collections
this.tasks = new Tasks();
this.chatMessages = new Messages();
// Init a 'me' object
window.me = new Me();
this.fetchStandardData(function (err) {
if (err) {
// Handle errors
}
// render the main viev
app.view = new MainView({
model: me
}).render();
// Start our router.
// Init our URL handlers and the history tracker
new Router();
app.history = Backbone.history;
// We have what we need, we can now start our router and show the appropriate page
app.history.start({pushState: true, root: '/'});
});
},
fetchStandardData: function (mainCallback) {
var self = this;
async.parallel([
function (cb) {
self.tasks.fetch({success: cb});
},
function (cb) {
me.fetch({success: cb});
}
], mainCallback);
}
}
As you can tell there's a handful of things we do regardless of the URL. Once we've got that sorted, then we init our router and start our history tracking (which enables back-button support).
The client router looks something like this:
var Backbone = require('backbone');
var TaskDetailPage = require('pages/taskDetail');
var FourOhFourPage = require('pages/fourOhFour');
module.exports = Backbone.Router.extend({
routes: {
'': 'home',
':slug/:slug/task/:taskid': 'memberTaskDetail',
...
},
// ------- ROUTE HANDLERS ---------
home: function () {
app.navigate(app.teams.first().chatUrl);
},
memberTaskDetail: function (teamId, memberId, taskId) {
var team = app.teams.get(teamId);
var member = team && team.members.get(memberId)
// make sure we found our models or send to an internal
// 'not found' page.
if (!team || !member) return this.fourOhFour();
// We may or may not have the task, so we just pass it in and try to get it from the view.
app.renderPage(new TaskDetailPage({
team: team,
member: member,
taskId: taskId
}));
},
fourOhFour: function () {
app.renderPage(new FourOhFourPage());
}
}
So, each of the routes listed at the top are turned into regexes by Backbone and linked to a handler function.
That function is called with the "arguments," a.k.a. parameters you specified as being dynamic in your routes.
I typically think of each handler's job as finding actual clientside model objects and then creating a "page" view that it passes to the application.
The app is responsible for taking that view and rendering it per conventions of the app. Usually we just have a "page view" be a specialized kind of Backbone view that also has a few standard methods for "show" and "hide." The app controller just calls "show" on the new one and "hide" on the currently active page, and the views add/remove themselves from the application layout's main "pages" container.
From this point forward we never need to do the launch sequence again. We'll just change the route, then the route handlers will render the appropriate page, and the page will ensure it has (or fetches) the data it needs.