$location / switching between html5 and hashbang mode / link rewriting $location / switching between html5 and hashbang mode / link rewriting angularjs angularjs

$location / switching between html5 and hashbang mode / link rewriting


The documentation is not very clear about AngularJS routing. It talks about Hashbang and HTML5 mode. In fact, AngularJS routing operates in three modes:

  • Hashbang Mode
  • HTML5 Mode
  • Hashbang in HTML5 Mode

For each mode there is a a respective LocationUrl class (LocationHashbangUrl, LocationUrl and LocationHashbangInHTML5Url).

In order to simulate URL rewriting you must actually set html5mode to true and decorate the $sniffer class as follows:

$provide.decorator('$sniffer', function($delegate) {  $delegate.history = false;  return $delegate;});

I will now explain this in more detail:

Hashbang Mode

Configuration:

$routeProvider  .when('/path', {    templateUrl: 'path.html',});$locationProvider  .html5Mode(false)  .hashPrefix('!');

This is the case when you need to use URLs with hashes in your HTML files such as in

<a href="index.html#!/path">link</a>

In the Browser you must use the following Link: http://www.example.com/base/index.html#!/base/path

As you can see in pure Hashbang mode all links in the HTML files must begin with the base such as "index.html#!".

HTML5 Mode

Configuration:

$routeProvider  .when('/path', {    templateUrl: 'path.html',  });$locationProvider  .html5Mode(true);

You should set the base in HTML-file

<html>  <head>    <base href="/">  </head></html>

In this mode you can use links without the # in HTML files

<a href="/path">link</a>

Link in Browser:

http://www.example.com/base/path

Hashbang in HTML5 Mode

This mode is activated when we actually use HTML5 mode but in an incompatible browser. We can simulate this mode in a compatible browser by decorating the $sniffer service and setting history to false.

Configuration:

$provide.decorator('$sniffer', function($delegate) {  $delegate.history = false;  return $delegate;});$routeProvider  .when('/path', {    templateUrl: 'path.html',  });$locationProvider  .html5Mode(true)  .hashPrefix('!');

Set the base in HTML-file:

<html>  <head>    <base href="/">  </head></html>

In this case the links can also be written without the hash in the HTML file

<a href="/path">link</a>

Link in Browser:

http://www.example.com/index.html#!/base/path


Fur future readers, if you are using Angular 1.6, you also need to change the hashPrefix:

appModule.config(['$locationProvider', function($locationProvider) {    $locationProvider.html5Mode(true);    $locationProvider.hashPrefix('');}]);

Don't forget to set the base in your HTML <head>:

<head>    <base href="/">    ...</head>

More info about the changelog here.


This took me a while to figure out so this is how I got it working - Angular WebAPI ASP Routing without the # for SEO

  1. add to Index.html - base href="/">
  2. Add $locationProvider.html5Mode(true); to app.config

  3. I needed a certain controller (which was in the home controller) to be ignored for uploading images so I added that rule to RouteConfig

         routes.MapRoute(        name: "Default2",        url: "Home/{*.}",        defaults: new { controller = "Home", action = "SaveImage" }    );
  4. In Global.asax add the following - making sure to ignore api and image upload paths let them function as normal otherwise reroute everything else.

     private const string ROOT_DOCUMENT = "/Index.html";protected void Application_BeginRequest(Object sender, EventArgs e){    var path = Request.Url.AbsolutePath;    var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);    var isImageUpload = path.StartsWith("/home", StringComparison.InvariantCultureIgnoreCase);    if (isApi || isImageUpload)        return;    string url = Request.Url.LocalPath;    if (!System.IO.File.Exists(Context.Server.MapPath(url)))        Context.RewritePath(ROOT_DOCUMENT);}
  5. Make sure to use $location.url('/XXX') and not window.location ... to redirect

  6. Reference the CSS files with absolute path

and not

<link href="app/content/bootstrapwc.css" rel="stylesheet" />

Final note - doing it this way gave me full control and I did not need to do anything to the web config.

Hope this helps as this took me a while to figure out.