1

So I have a bit of a problem.

I'm in a situation where I need to have multiple Backbone.Routers which handle their own routes accordingly etc. and I dynamically load them based on what the main router (Router 1 in the following example) knows about the route currently.

The main problem I am encountering though is something like this.

  • Router1 loads
  • Backbone.history.start()
  • Router1 loads Router2
  • Router2 dosen't do anything because history has started already

Is there any possible way I can get router2 to look at the current history fragment without potentially calling the routes in router1 again?

IE don't manually call Backbone.history.loadUrl(Backbone.history.getFragment());

Edit:

The main goal is that right now I have two views and well would obviously like a router per view. It makes no sense to have one huge router considering that in the future there may be n views that knows about every single individual view.

adrian
  • 2,326
  • 2
  • 32
  • 48
  • If you need a dynamic way of handling routes and your main router will determine how those dynamic routes are generated, why don't you create a Backbone collection of regex expressions and callback functions that you use for your second routes and pass both the url, regex and callback function to a method inside your main router. This is generally how routes are handled. Just one way, I'm sure there is a better way to do this. – Kalpers Mar 28 '13 at 11:39
  • Hm this might work, do you have any method details? – adrian Mar 28 '13 at 15:52

2 Answers2

1

I suggest you try to look at MarionetteJS which is a great framework for building composite applications with Backbone. Specifically look at the source code of the MarionetteJS example app. What it does is separate the application into several sub-apps. Each sub-app has its own router, but they all define the separate routers on the parent app. When the parent app initializes, all routers are created, and only then Backbone.history.start() is called. I realize that this answer requires you to dive into Marionette, which has a steep learning curve, but I think it's totally worth it. We've built the entire architecture of the SOOMLA designer web-app on top of it. Marionette has proven to be a great solution when you want to outgrow your repetitive Backbone boilerplate code. Kudos to Derick Bailey for an awesome open source framework.

Community
  • 1
  • 1
Gur Dotan
  • 922
  • 8
  • 12
0

Could you please provide a jsfiddle which reproduce your case? Because you could normally do that (I personally have an app instantiating a router, starting the history, instantiating several other ones, and it works perfectly fine.)

Until such time, here are some information about routers though:
- when you instantiate a router, the routes are bound to Backbone.history (one unique object)
- this implies that you can't expect both routers to execute a callback
- it also implies that there is a fixed order: the last instantiated router's routes will be checked first

Edit:
Ok, I guess you want both routes executed because you expect someone to get directly into tab1/stuff.
Ugly way: you can stop Backbone.history (Backbone.history.stop()) and start it right afterward, the router2's routes would be bound...
Other possibility: why don't you put all your routes in your main router? Well I guess if you really have too many that's understandable.
Last possibility (that I can think of): use the fact that the last router's routes are tested first, and that's what you need. Change your main router's routes, add a generic one that will catch what you need (for example tab1). Don't do anything, navigate backward to /tab1. Prepare 2 navigates, like this:

this.navigate('/tab1', {trigger: true});
this.once('someEvent', function() {
    this.navigate('/tab1/stuff', {trigger: true});
});

If you have generic enough URLs, you can replace tab1 & stuff with arguments you would match with your generic route.

Edit 2:
Ok here's an edit assuming everything I wrote in my last comment and that you access your Backbone views with a hashtag (or an URL) like view/action. I'll try to be the more thorough as I can be (because I still don't have all the details of your problem).

This jsfiddle shows the principle. Now, there's still the fact that it will mess with the client's history (there may be a way to avoid that in Backbone I think, you'd have to look into that if it's a problem for you).

Now, the fact that there may be several other problems. The least of them could be the boilerplate in the secondary routers (you have to put view/ before any route). There are solutions for that, but that would be going too deep. The bigger one is the following:
I've already said it but only one route will be matched. So your main router CANT be used to deal with the fact the the client will change views (say going from view1/action1 to view2/action2, router2 already loaded before). The action2 will be executed, but if you reloaded your views in your main router, that won't be done.
Just as a last comment, you can modify the Routers core initialize method after creating your main router to add boilerplate behavior (reload your view?): here's an example that may suit you.

Loamhoof
  • 8,293
  • 27
  • 30
  • https://gist.github.com/amchang/5264260, you get the main idea, ideally in this situation, I would want router2 routes to run even though it's not created technically when history starts. – adrian Mar 28 '13 at 15:50
  • So with your last suggestion are you basically saying special case it, wait for an 'async'event then manually navigate? – adrian Mar 28 '13 at 18:00
  • That was a bit of my code, I fear the 'async' event was something I added (being at home I can't look into it now, I'll check tomorrow). But the idea is to listen to something that will tell you you can navigate once more because everything is loaded (here your second router). – Loamhoof Mar 28 '13 at 18:16
  • I wrote an update to the original question, maybe you can give a different approach – adrian Mar 28 '13 at 19:23
  • Could you give really more details please? From what I understood: you have a main router that will route to one of your view (I guess your views are equivalent to server-side MVC views, ie more or less different pages). From there on, you'd like to have one router per view, so your secondary routers are instantiated only when they really are needed. And of course, it should work if the user comes directly to one of your secondary route (creates the view + executes the action inside it). Is that it? – Loamhoof Mar 28 '13 at 22:41