Question

The routing in Angular makes use of the hash character in the URI path, for example

http://localhost/#currencies/10

Is it possible to remove the # sign? If yes, how? I want that the URL should appear like this:

http://localhost/currencies/10 

This looks much prettier.

2 Answers

By default, Angular routes URLs with a hashtag. You can easily remove the hashtags from the Angular URLs and make them look clean. In the config phase, you need to inject the $locationProvider service and simply set the html5Mode to true.

angular.module('admin', ['ngRoute'])
.config(function ($routeProvider, $locationProvider) {
    $routeProvider.when('/admin/currencies', {
        templateUrl: 'views/curr.html', controller: 'CurrencyController'
    });
    ...
    //Turn on HTML5 mode in your Angular module's config block
    $locationProvider.html5Mode(true);
}

In your HTML, you do not need to use the # (hashtags) anymore in the href:

<ul>
    <li><a href="admin/currencies">Currencies</a></li>
    <li><a href="admin/countries">Countries</a></li>
</ul>

The tag is used to specify a default URL for all links on a page. Its href attribute specifies the base URL for all relative URLs in the page. When you set the html5mode to true, you also need to set the <base> in the <head> tag and it makes the routes relative to the base URL. For example, if you set the base tag like this:

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

and if

<a href="admin/currencies">Currencies</a>

is there, and then when you click on the Currencies link, it will resolve to this URL: /admin/currencies.


Michelle's answer is correct but there is more to it. In addition to setting HTML5 mode to true in Angular, you need to enable the server-side rewrites.

The problem occurs when the user refreshes a page or paste a URL directly. This is because the browser has no way of knowing that this is not a real URL. In other words, without the hash character in the URL, it takes it as a literal URL and attempts to navigate there when the user does a refresh. In this scenario, it just sends the GET request to the server like this...

GET http://localhost/currencies/10

and the server responds with this message...

Cannot GET /currencies/10

From the Angular documentation... Using the html5mode mode requires URL rewriting on server side, basically you have to rewrite all your links to entry point of your application (e.g. index.html).

This means that you need a setup on your server that automatically redirects the user to your Angular index page, so that the Angular routing can take over from there. On the other hand, if you use the # symbol, it requires no server side configuration.

To allow for this, you need to write a catch-all route in your Node/Express web server as follows:

app.get('/*', function(req, res) {
    res.sendfile('index.html');
});

This means that before each request gets to your Angular app, it has to pass first through the server-side routing, which should rewrite all requests to point to index.html which is the Angular app's entry point.