I think I don’t quite get the idea behind the proper usage of Backbone routers. Here’s what I’ve got:
I have some data that I fetch from the server when the page loads and then pack it into models and collections. The number of those models and collections is indefinite. I want to use the router to be able to render the certain collection’s view directly from the start.
The problem is: Backbone router starts up early, and since I ask it to access a certain view and trigger its render
action, it cannot do that, because those views are not yet created. That means I actually have to make my routes start up after the fetch is complete.
I don’t know if this is a proper way to do it, but the only idea I came up with is to:
Backbone.history.start();
bit into a separate top-level-accesible function (i.e. prepare to call it manually later on).success
callback for my collections’s fetch()
_.defer()
and _.once()
.This works, but it sure looks very weird:
Routers:
window.startRoutes = _.once(function() {
var AccountPage = Backbone.Router.extend({
routes: {
'set/:id': 'renderSet',
},
renderSet: function(setId) {
/** … **/
// Call the rendering method on the respective CardView
CardsViews[setId].render();
}
});
var AccountPageRouter = new AccountPage;
Backbone.history.start();
});
Collection:
window.CardsCollection = Backbone.Collection.extend({
model: Card,
initialize: function(params) {
/** … **/
// Get the initial data
this.fetch({success: function() {
_.defer(startRoutes);
}});
},
});
So my question is… am I doing it right? Or is there a better way to do this (must be)?
A backbone router is a router designed to be used to construct backbone networks using leased lines. Backbone routers typically do not have any built-in digital dial-up wide-area network interfaces.
Backbone. js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.
There is only method named "start" can be used to manipulate the Backbone. js history.
You can use the Backbone. Model without jQuery, but Backbone. View will require either jQuery or Zepto, just like the docs state. Chances of not using view and router is low enough.
You can define your router ahead of time; it won't do anything until you call Backbone.History.start().
You can bind the "reset" event on your collection to start history like this:
my_collection.bind("reset", _.once(Backbone.History.start, Backbone.History))
Then the router will start doing stuff when your collection is fully loaded. I'm not sure if this is exactly what you're looking for (since you mentioned having a variable number of collections).
I have a similar situation, except that I know in advance which collections I want to have loaded before I start routing. I added a startAfter method to my Router, like so:
window.Workspace = new (Backbone.Router.extend({
. . .
startAfter: function(collections) {
// Start history when required collections are loaded
var start = _.after(collections.length, _.once(function(){
Backbone.history.start()
}))
_.each(collections, function(collection) {
collection.bind('reset', start, Backbone.history)
});
}
}));
and then after I've setup my collections
Workspace.startAfter([collection_a, collection_b, ...])
This could be adapted to work with standalone models too, although I think you'd need to bind to something other than the 'reset' event.
I'm glad I read your example code, the use of _.once and _.defer pointed me in the right direction.
I'm just checking in my .render()
method that all required fields are filled, before using it. If it's not filled yet - i'm rendering an 'Loading...' widget.
And all my views are subscribed to model changes, by this.model.bind('change', this.render, this);
, so just after model will be loaded, render()
will be called again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With