0

I have single page web application is written on backbonejs. I use different routes and each route corresponds a controller. When I load my app root URL (myapp.com/) or any non-root URL without params (myapp.com/somelocation) it works correctly. But when I try to load my app directly to any location with query params (i.e. myapp.com/somelocation?z=search) I have some trouble. App renders twice - first with correct controller that correspond to myapp.com/somelocation?z=search and second time with controller that correspond to myapp.com/somelocation.

Routes table look like this:

routes: {
        'login': 'login',
        'home': 'home',
        'timeline?*query': 'timelineWithQuery',
        'timeline': 'timeline',
         ...
        '*path': 'defaultRoute'
    }, ...

Controllers look like this:

defaultRoute: function() {
    router.navigate('home', {trigger: true});        
},

login: function(args) {
    var controller = new App.PageController.Mobile.AuthPageController($('body'));
    controller.executeLogin(args);
},

timeline: function(args) {
    var controller = new App.PageController.Mobile.TimelinePageController($('body'));
    controller.executeTimeline(args);
}, ...

Document.ready script looks like this:

// ...
router.navigate(window.location, {trigger: true});
// ...

If I don't call router.navigate(window.location, {trigger: true}); explicitly no one controller renders my application start page. When I call it app works correctly until I try to start from myapp.com/timeline?foo=bar URL. And if I do this my app is rendered twice (without page reloading).

Any suggestions? What is common document.ready bootstrap pattern for backbonejs-driven single page apps with rich routing scenarios?

Ivan Velichko
  • 5,581
  • 3
  • 35
  • 72

1 Answers1

1

The navigate uses location.pathname (by pushState) or location.hash, so the location.queryString is not a part of the navigation procedure. I am not sure how this row: 'timeline?*query': 'timelineWithQuery', is transformed to regex, btw it does not really matter because you will run that regex every time on my/path, not on my/path?queryString.

You have to define every route before Backbone.history.start({pushState: true}). When you call it, it should run the current route, so you don't have to call navigate manually after that.

Mrchief
  • 70,643
  • 19
  • 134
  • 181
inf3rno
  • 20,735
  • 9
  • 97
  • 171
  • Ofcourse I use Backbone.history.start() before call router.navigate(window.location, {trigger: true}). And I still have troubles with some routes with query string. – Ivan Velichko Jul 14 '13 at 20:26
  • Looks like I should use Backbone.history.start({root: window.location}) instead of router.navigate(window.location, {trigger: true}) in my document ready callback. But now I have some troubles with concatenation of url parts. After call historty.start my URL looks like windows.location + windows.location.path. – Ivan Velichko Jul 14 '13 at 20:53
  • Please read more about REST services. The url.path is a resource identifier, you have to use only that for navigation. After you found the resource you can use the url.queryString to filter or modify the output. You should not inject the url.queryString to the navigation, that's a bad practice... You can set and modify the url.path with Backbone, it does it automatically, so you never have to use the window.location by navigation... First you create your Router instances. After that in domReady you starts the history. After that the history automatically does everything else. – inf3rno Jul 14 '13 at 20:57
  • I have separate REST API and web client.API looks like pure resources with query string filtration if needed.Web client has their own urls.WebApp retrieves data from API and renders pages. Pages are not directly correspond to API resources.URLs in app correspond to different app screens(client-side states). Reloading a page must save client-side state (restoring it through path+query string).Query string in app can be part of location not only filtration. myapp.com/tl corresponds to timeline screen and myapp.com/tl?z=bndg5 url corresponds to binding widget onto timeline page for item with id 5 – Ivan Velichko Jul 14 '13 at 21:40