Search code examples
angularjsurl-routingdeep-linkinghashtag

angularjs v1.3.15 deep linking / routing / path no longer working with hashtag (Migrated from v1.2.3)


I am very new to angular and working on some code that I wanted to upgrade the angular version from 1.2.3 to 1.3.15 (which I have also never done before). When I did, the navigation links on my index page stopped working; rather it seems like the router.js falls through to my $routeProvider.otherwise case and redirects to /home (you can see the refresh in my jumbotron). However, I also notice that when I click on the links, my url goes from localhost:8888/home to localhost:8888/home# or localhost:8888/home#home or localhost:8888/home#info, but the page routes don't work (the home page gets refreshed instead) - like the route is just appended to /home and it doesn't know what to do.

When I remove the deep linking ( hash / pound / # ) from the links in index.html, the code appears to work again, but I don't really understand why. It's highly likely I'm misunderstanding something in the breaking changes from 1.2 to 1.3, but the documentation made it seem like using # is still supported in 1.3.

By "upgrading" I replaced my angular.js, angular-resource.js, and angular-route.js in my project with their newer versions. I am using Apache karaf, and tested in both Chrome and Firefox with the same results.

Shortened code below:

Here is the index.html code that works in 1.2.3 and breaks in 1.3.15 (I used both # and #home to test if there would be a difference):

  <div class="navbar navbar-inverse navbar-fixed-top">
  ...
      <a href="#" class="navbar-brand">My Project<small></small></a>
      ...
      <div class="collapse navbar-collapse navHeaderCollapse" data-ng-controller="NavController">
        <ul class="nav navbar-nav navbar-right">
          <li class="{{navData['Home'].css}}"><a href="#home">Home</a></li>
          <li class="{{navData['Info'].css}}"><a href="#info">Info</a></li>
        </ul>
      </div>
    </div>
  </div>

My router.js looks like:

angular.module("app").config(function ($routeProvider, $locationProvider) {

    $locationProvider.html5Mode(true);

    $routeProvider.when('/home', {
        templateUrl: "home.html",
        controller: "HomeController",
        isPublic: false
    });

    $routeProvider.when('/info', {
        templateUrl: "info.html",
        controller: "InfoController",
        isPublic: false
    });

    $routeProvider.otherwise({ redirectTo: '/home' });

});

With 1.3.15, when I replace the hash / pound / # signs in index.html, with "/" for Home and "info" instead of the "#info", everything seems to work again.

I also tried upgrading potential dependencies to the following:

  • ui-bootstrap-tpls-0.13.0.js (was 0.6.0)
  • jquery-2.1.4.js (was 2.0.3)

I am using:

  • bootstrap.js (using 3.0.0)

I also have some additional libraries but didn't know if they are relevant to this. Let me know if I should add them to the list.

I attempted to simulate what I am seeing in plunker here: Angularjs v1.3.15 test # redirect

But the links appear to be working with the exception of when you click a link with just "#" as the href, the page template isn't loaded at all. So I don't know if the issue is related or completely different.

A few suggestions I've looked into (but maybe missed something):

  • I did see that people are upgrading ui-router, but I'm not currently using it; should I be? (Though plunker seems to be working with angular-route.js)
  • html5 is not playing nice in all arenas, but it appears configured in my code?
  • fixing the server to allow #, which I think is already done since the code used to work correctly

Thanks in advance for the help! If you could point me in the right direction that would also be appreciated!


Solution

  • The hash has a specific meaning in the HTML specification. It targets an element on a page. If you are on the page localhost:8888/home and click on the link localhost:8888/home#info the browser would jump to the element with the id info, if there was one. Consequently nothing happens if the element doesn't exist.

    Angular intercepts clicks and url changes and allow you to change routes instead. To avoid any confusion (or unintentional behavior) Angular has two conventions. The first is using a prefix. It's optional and the one suggested is !. That's why this mode is also called the Hashbang mode, links to routes would start with #!.

    The second, and more important one, is that routes start with /. So it's href="#/" and href="#/info". And this works no matter what version of Angular you are using. Of course, this fixes your plunker.

    If you want to use hashes then don't activate the HTML5 mode.

    One remark about your last point: The server doesn't care about #, since it only concerns the client.