71

When enabling the html5Mode in AngularJS via $locationProvider.html5Mode(true), navigation seems to be skewed when you land on a page deeper in the site.

for example:

  • http://www.site.com
    when i navigate to the root, i can click all links in the site, Angular's $routeProvider will take over navigating through the site and loading the correct views.

  • http://www.site.com/news/archive
    but when i navigate to this url (or hit refresh when I'm on a deeplink like the above one...) this navigation is not working as I expect it to. first of all, our as the Documentation for $locationProvider.html5Mode specifies, we catch all urls on the server, similar to the otherwise route in angular, and return the same html as the root domain. But if I then check the $location object from within the run function of angular, it tells me that http://www.site.com is my host and that /archive is my path. the $routeProvider arrives in the .otherwise() clause, since i only have /news/archive as a valid route. and the app does weird stuff.

Maybe the rewriting on the server needs to be done differently, or I need to specify stuff in angular, but currently i'm clueless as to why angular see's the path without the /news segment included.

example main.js:

// Create an application module
var App = angular.module('App', []);

App.config(['$routeProvider', '$locationProvider', function AppConfig($routeProvider, $locationProvider) {

    $routeProvider
        .when(
        '/', {
            redirectTo: '/home'
        })
        .when('/home', {
            templateUrl: 'templates/home.html'
        })
        .when('/login', {
            templateUrl: 'templates/login.html'
        })
        .when('/news', {
            templateUrl: 'templates/news.html'
        })
        .when('/news/archive', {
            templateUrl: 'templates/newsarchive.html'
        })
        // removed other routes ... *snip
        .otherwise({
            redirectTo: '/home'
        }
    );

    // enable html5Mode for pushstate ('#'-less URLs)
    $locationProvider.html5Mode(true);
    $locationProvider.hashPrefix('!');

}]);

// Initialize the application
App.run(['$location', function AppRun($location) {
    debugger; // -->> here i debug the $location object to see what angular see's as URL
}]);

Edit as per request, more details on the server side: the server side is organised by the routing of zend framework, and it handles it's own routes (for serving data to the frontend on specific /api urls, and at the end, there is a catch-all route if no specific other route is bound, it serves the same html as the root-route. so it basically serves the homepage html on that deeplinked route.

Update 2 after looking into the problem we noticed this routing works fine as it is, on Angular 1.0.7 stable, but shows the above described behaviour in the Angular 1.1.5 unstable.

I've checked the change-logs but haven't found anything useful so far, I guess we can either submit it as a bug, or unwanted behaviour linked to a certain change they did, or just wait and see if it get's fixed in the later to be released stable version.

Sander
  • 13,301
  • 15
  • 72
  • 97
  • How are you doing it on the server? – John Ledbetter Aug 13 '13 at 16:54
  • @JohnLedbetter if you need more info than the info I added on server side code, i can ask my collegues to give me more specific details tomorow. I myself work at the front-end of this project mostly. – Sander Aug 14 '13 at 00:01
  • thanks for the update, I played with the 1.1.5 unstable version a while ago and it did indeed have quite a few bugs. It might be worth trying the new [1.2.0-rc1](http://code.angularjs.org/1.2.0rc1/) release. – John Ledbetter Aug 14 '13 at 14:59

5 Answers5

84

Found out that there's no bug there. Just add:

<base href="/" />

to your <head />.

samura
  • 4,375
  • 1
  • 19
  • 26
  • i have to try that :) i'll get back to you tomorrow as i will definately try this... However currently we are already running 1.2.0 rc2 without problems. have yet to test 1.2.0 final though. but i doubt it will give issues since we already have the RC2 for it. so we already changed it up into the separate module for routing... – Sander Nov 13 '13 at 23:01
  • 7
    Watch out, as this will break all relative and anchor links on your pages unless you use a workaround. – jjt Nov 15 '13 at 10:38
  • 1
    I think the HTML5 spec says that base needs to point to an absolute URI – Nikos Apr 07 '14 at 09:19
  • 12
    Alternatively, use the `requireBase` property [described here](https://docs.angularjs.org/error/$location/nobase). Set `$locationProvider.html5mode({ enabled: true, requireBase: false });` and you don't need to use a `` in your HTML. I ran into this when using SVG marker references (e.g., to load a linear gradient from a separate SVG file, a.k.a. paint server), which are thrown off by `` (in fact, that's why this option was added in the first place - see: https://github.com/angular/angular.js/issues/8934#issuecomment-56568466. – Bungle Jan 05 '15 at 21:10
12

This was the best solution I found after more time than I care to admit. Basically, add target="_self" to each link that you need to insure a page reload.

http://blog.panjiesw.com/posts/2013/09/angularjs-normal-links-with-html5mode/

Larry Eitel
  • 1,397
  • 5
  • 19
  • 37
9

This problem was due to the use of AngularJS 1.1.5 (which was unstable, and obviously had some bug or different implementation of the routing than it was in 1.0.7)

turning it back to 1.0.7 solved the problem instantly.

have tried the 1.2.0rc1 version, but have not finished testing as I had to rewrite some of the router functionality since they took it out of the core.

anyway, this problem is fixed when using AngularJS vs 1.0.7.

Sander
  • 13,301
  • 15
  • 72
  • 97
7

My problem solved with these :

1- Add this to your head :

<base href="/" />

2- Use this in app.config

$locationProvider.html5Mode(true);
Saeed
  • 5,413
  • 3
  • 26
  • 40