4
votes

I am using coenraets' Employee Directory as a starting point for my Backbone application. The first thing I would like to do is to change routing to use the HTML5 PushState instead of hash-hash bang-bangs.

First I have changed:

<ul class="nav">
  <li class="active"><a href="/">Home</a></li>
  <li><a href="/contact">Contact</a></li>
</ul>

Then:

Backbone.history.start({ pushState: true });

Now if you go to localhost:8000/contacts instead of localhost:8000/#/contacts it gives 404 error, regardless if you clicked on the Navbar or typed the URL manually.

Am I doing something wrong? Thanks.

UPDATE: I added this code and it works fine now when I click on a link [stateful]. But if I refresh the page while I am in localhost:8000/contacts I still get 404 error [stateless].

$(document).on('click', 'a:not([data-bypass])', function(e){
  href = $(this).prop('href')
  root = location.protocol+'//'+location.host+'/'
  if (root===href.slice(0,root.length)){
    e.preventDefault();
    Backbone.history.navigate(href.slice(root.length), true);
  }
});

Update 2

In addition to the above code, I have added the following route in my Express.js app. If you look closely you'll notice the URL bar changes from localhost:3000/#contact to localhost:3000/contact although it happens pretty fast. Perhaps there is a better way to do this thing, but I am satisfied with this approach for time being.

app.get('/contact', function(req, res) {
  res.redirect('/#contact');
});
2
You need to do a server-side URL rewrite, from /contact, etc, to the root page.McGarnagle
Hence why pushState is disabled by default.idbehold
@dbaseman Thanks, I updated my question. Is this the right approach?Sahat Yalkabov
@TwilightPonyInc. no, it can't be a redirect, has to be a rewrite -- that is, when the client requests /contact, the server returns the content for the root. I'm not familiar with Express/Node, so I don't know what the syntax would be ...McGarnagle

2 Answers

2
votes

Assume that you have just one html file. You need use something like that for all your routes display the same html file:

app.configure(function () {

  // static files
  app.use(express.static(__dirname + '/public'));

  // default html file (with any request)
  app.use(function (req, res) {
    var contents = fs.readFileSync(__dirname + '/public/index.html');
    res.send(contents.toString());
  });

});

I don't know if is useful for you. It was for me.

0
votes

No, It's might not be the best way in your Update 2.

Since what we are doing is a Single Page Application, so what we need to do is just:

Server end:
For request like: http://yourdomain.com/whatever, you just return the index page.

Frond end:
Nothing. Backbone will handle it automatic, It will change the url http://yourdomain.com/whatever to http://yourdomain.com/#whatever automatic. And since we use {pushstate: true}, Backbone will change it to http://yourdomain.com/whatever for user to look. All of this will done transparent.
(All you need to do in frond end is to remove the # in your url link. )