Graceful routing fallback in hybrid AngularJS apps

My current favourite way of working with the otherwise-awesome AngularJS framework is to only apply it to those sections of a page that actually need Angular-behaviour, and let common PHP solve the rest (what I call a “hybrid Angular app”, lacking a better term). While Angular does offer stuff like ngRoute and uiRouter to handle “HTML5-mode routing”, this comes with some other problems, the most notable being search engine indexing. While there are solutions for that they have their own drawbacks, so today I’d rather just have a regular site with some <element my-awesome-directive/> where needed.

I did however run into a problem: IE<10. (Yes, it’s Explorer again…) IE9 and before don’t support the HTML5 history API of course, so Angular has a fallback using hashed URLs. Fine. I assumed that as long as you’re not actually using routes, Angular would leave your URLs alone.

I was wrong.

For any regular URL /foo/, Angular insists on redirecting to /#/foo/ in older Explorers, which of course will just render the homepage with a useless hash URL since I’m not actually letting Angular handle the routing. Bummer. The solution turned out to be simple enough though: don’t force $location.html5Mode(true) if the browser doesn’t even support it. This will cause your IE<10 to just treat all URLs as regular links, will let Angular handle HTML5 URLs where you do define them (e.g. an image gallery) in supporting browsers, will still allow old IEs to run all other Angular code and thus provides the perfect graceful fallback.

Hence:

angular.module('mythingy', []).config(['$locationProvider', $locationProvider => {
    if (!!(window.history && window.history.pushState)) {
        $locationProvider.html5Mode(true);
    }
}]);