I was under the impression that Angular would rewrite URLs that appear in href attributes of anchor tags within tempaltes, such that they would work whether in html5 mode or
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.
The documentation is not very clear about AngularJS routing. It talks about Hashbang and HTML5 mode. In fact, AngularJS routing operates in three modes:
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:
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#!".
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
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
I wanted to be able to access my application with the HTML5 mode and a fixed token and then switch to the hashbang method (to keep the token so the user can refresh his page).
URL for accessing my app:
http://myapp.com/amazing_url?token=super_token
Then when the user loads the page:
http://myapp.com/amazing_url?token=super_token#/amazing_url
Then when the user navigates:
http://myapp.com/amazing_url?token=super_token#/another_url
With this I keep the token in the URL and keep the state when the user is browsing. I lost a bit of visibility of the URL, but there is no perfect way of doing it.
So don't enable the HTML5 mode and then add this controller:
.config ($stateProvider)->
$stateProvider.state('home-loading', {
url: '/',
controller: 'homeController'
})
.controller 'homeController', ($state, $location)->
if window.location.pathname != '/'
$location.url(window.location.pathname+window.location.search).replace()
else
$state.go('home', {}, { location: 'replace' })
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 $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.