Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js router and redirection problems with Internet Explorer

bit of a weird one and I'm a little baffled...

I have a page, on that page is the following (well, with a few name changes):

$(document).ready(function() {
  var router = new App.Routers.ExampleRouter();
  Backbone.history.start({pushState: true});
})

The router goes on its way to instantiate some collections, views etc. Everything is working absolutely fine in Chrome, Safari, Firefox and Opera. But not in IE 8 or 9 (maybe 10 too, I haven't tested).

In IE8 or 9 when the page is first requested it starts to load, but as soon as the document is ready (and the router therefore instantiated and History started) the page redirects to the site root.

There's nothing in the console that I can see prior to the redirect. There's no code anywhere else that could be somehow doing it - I mean, we have a large codebase, so it's always a possibility, but there's nothing that deals with routing or the History API that could be conflicting.

The weird part is if the pushState: true option is removed, the page doesn't redirect, it loads fully as it should - the router doesn't go on its way to do anything as it's now expecting hashbang style routes, but it at least doesn't kick you back to the site's root. Add the option back in, and it breaks again...

So, my first thought was obviously "Well...the History API isn't supported in IE8 or 9...must be it" but then Backbone.js is supposed to revert back to hashbang style URLs for those older browsers, so it can't be that.

What on earth is causing just IE to redirect back to the homepage when dealing with a Backbone.js router?

EDIT

(The below can probably be ignored now as EDIT 2 proves it did nothing, although yay for removing trailing commas)

Okay, so after a little debugging and really clutching at straws I found that the router wasn't actually being instantiated - no initialize method being called, no ability to call custom methods on the router (I'd just made a silly method to alert and console.log) and called it just after var router = new App.Routers.ExampleRouter();.

Calling the method was returning an error along the lines of: "object doesn't support that property or method" (all of this is just IE again, fine in other browsers). This wasn't unique to the router though, I invoked a new model too and did the same things, same thing...just wasn't being "seen". A Google of the object error suggested trailing-commas. Right enough there were some in the codebase, I removed all of them and it seemed like things were going well. All of a sudden the router (and model) were very much there - initialize method called, custom method called etc. I figured the commas may have stopped all of the JS being parsed (we concatenate multiple files).

I'd obviously been doing all of this with the pushState option removed. I then added pushState: true back in genuinely thinking that would fix it what with the above having happened. I'd thought at the time "Ah, the router never actually 'existed' so maybe Backbone.History.Start({pushState: true}) being called sent it looking for a route, and none existed due to the router not being instantiated, and the kick-back to the homepage was just some sort of side-effect" but alas, no, the exact same thing is still happening. Add in the pushState: true option and the page just doesn't load, and kicks you back to the homepage.

EDIT 2

Okay, so I've tried some further things to no avail. I made a completely separate blank page that pulls in jQuery, Backbone.js and Underscore.js via a CDN and contains some barebones JavaScript for creating a router, instantiating it and calling Backbone.History.Start(). The code in it's entirety for that page is:

<!DOCTYPE html>
<html>
  <head>
    <title>Test IE</title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery-1.8.0.min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
    <script>
      $(document).ready(function(){

        App = {
          Routers: {

          }
        };

        App.Routers.RouterTest = Backbone.Router.extend({
          routes: {
            "ietest.html" : "helloWorld"
          },

          initialize: function() {
            console.log("router init");
          },

          helloWorld: function() {
            alert("helloWorld!")
          }
        });
        router = new App.Routers.RouterTest();
        Backbone.history.start({pushState: true});
      });
    </script>

  </head>
  <body>

  </body>
</html>

That's it, completely barebones, no influence from any other site assets etc. The exact same thing still happens. All browsers do what is expected, except IE (tested on 8 and 9) which again starts to load the page, then executes the route and all of a sudden redirected back to the homepage. If I turn pushState off and use hashbangs everything works as expected - so routing does 'work' for me in IE, just not with pushState set to true.

I can't see that this is a front-end thing anymore as I've stripped away everything I can? Is there any way this is a server related thing? The back-end is Ruby on Rails and the problem is exhibited locally and on staging / live servers. Or have I grossly misunderstood the way that Backbone.js degrades pushState to hashbangs with IE?

EDIT 3

I've uploaded a video of the problem

like image 486
Kerry Avatar asked Aug 21 '12 19:08

Kerry


3 Answers

Internet Explorer doesn't support pushState until IE 10, see

http://caniuse.com/#search=pushState

Edit:

To start History with an optional pushState you could go with this:

Backbone.history.start({pushState: "pushState" in window.history});
like image 184
Thor Larholm Avatar answered Nov 05 '22 22:11

Thor Larholm


It looks to me that your application is not being served from the root URL (/).

You're requesting http://example.com/sub/ietest.html, and Backbone redirects to http://example.com/#sub/ietest.html.

You probably want to initialize Backbone.history specifying a root URL:

Backbone.history.start({pushState: true, root: '/sub/'});

I haven't really dug into the source code of your page (and the JS is minified), but this seems to be the case. Maybe root: '/bible/'?

like image 38
Bertrand Marron Avatar answered Nov 05 '22 20:11

Bertrand Marron


try to comment all the console.log() calls. In my case that was the problem for ie9. Yes, I'm also asking the question that why :-), very odd

(I didn't use pushState, but that should not matter I guess)

like image 33
miro Avatar answered Nov 05 '22 20:11

miro