Search code examples
javascriptbackbone.jspushstatebackbone-routinghtml5-history

Backbone router with no hashbangs


I've set up a super simple Backbone app with just a router and two views to try and nail down the correct way to handle routing with no hashbangs.

var Router = Backbone.Router.extend({
    routes: {
        '': 'index',
        'episodes': 'episodes'
    },

    index: function () {
        var view = new IndexView();
        view.render();
    },

    episodes: function () {
        var view = new EpisodesView();
        view.render();
    }
});

var IndexView = Backbone.View.extend({
    el: $('#primary'),
    render: function () {
        console.log('index view');
    }
});

var EpisodesView = Backbone.View.extend({
    el: $('#primary'),
    render: function () {
        console.log('episodes view');
    }
});

var router = new Router;
Backbone.history.start({pushState: true});

I realize that the history object allows forward and backward navigation between pages, which is great. However, the way it's actually implemented seems a little messed up to me.

For instance, I created a simple MAMP server to serve an index.html file and the JS file. Navigating to http://backbone:8888/, the console logs index view like I'm telling it to. However, navigating to http://backbone:8888/episodes (by typing it into the address bar) returns a 404. BUT, if I navigate to http://backbone:8888/#episodes, the URL redirects to http://backbone:8888/episodes (without the hashbang) and I get episodes view logged to the console, which obviously means it's hitting that EpisodesView view.

From here, I can go back and forth between the index and episodes views. (back hits /, forward hits /episodes). That's all fine and dandy until I hit refresh while on /episodes again. 404...

So my question is this: how can Backbone be set up to handle URLs without relying on hashbangs? Everything I've found on the topic says "oh just pushState!". Well, I'm using pushState and, like I described above, you can't hit a URL like /episodes directly without getting a 404.


Solution

  • When you use push state, pages are served from the back end, which means that you have to define a corresponding route in your back end that corresponds to a front end route.

    If the back end doesn't find the requested route, then it will deliver a 404 message, because it won't know what to serve. In your case, the episodes view gets triggered at the front end level, but the browser doesn't have a DOM to render the view when the page gets refreshed because nothing was served.

    By default, the route http://backbone:8888/ will serve the index file because this is how the webserver is configured.
    I'm not sure what back end technology you are using, but for serving a file from http://backbone:8888/episodes, just make sure that your back end has a router set up that serves the requested route and it should work.