$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
- add to Index.html - base href="/">
Add $locationProvider.html5Mode(true); to app.config
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" } );
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);}
Make sure to use $location.url('/XXX') and not window.location ... to redirect
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.