angularjs provides an abstraction layer over URLs (and their behavior) in the form of the $location service. This service masks the difference between the hashbang and the HTML5 URL modes allowing us, application developers, to work with a consistent API regardless of the browser and the mode being used. But the $location service does more heavy lifting, by providing the following functions:

  • Provides convenient, clean API to easily access different parts of the current URL (protocol, host, port, path, query parameters, and so on)
  • Lets us to programmatically manipulate different parts of the current URL and have those changes reflected in the browser’s address bar
  • Allows us to easily observe changes in different components of the current URL and take actions in response to those changes
  • Intercepts the users’ interactions with links on a page (such as clicking on the <a> tags) to reflect those interactions in the browser’s history

Understanding the $location service API and URLs

Before we see practical examples of using the $location service, we need to get familiar with its API. Since the $location service works with URLs, the easiest way to get started is to see how the different components of a URL map to the API methods.

Let’s consider a URL that points to a list of users. To make the example more complex, we will use a URL that has all the possible components: a path, a query string, and a fragment. The essential part of the URL could look as follows:


We could decipher this URL as: in the administration section, list all users that are active and scroll to the bottom of the retrieved list. This is the only part of a URL that is interesting from the point of view of our application, but in reality a URL is the “whole package”, with a protocol, host, and so on. This URL in its full form, will be represented differently, depending on the mode (hashbang or HTML5) used. In the following URL, we can see examples of the same URL represented in both modes. In HTML5 it would look as follows:

In hashbang mode it would take its longer, uglier form, which is as follows:

Regardless of the mode used, the $location service API will mask the differences and offer a consistent API. The following table shows a subset of the methods available on the API:

Method Given the above example, would return
$location.url() /admin/users/list?active=true#bottom
$location.path() /admin/users/list
$ {active: true}
$location.hash() Bottom

All of these methods are jQuery-style getters. In other words, they can be used to both get and set the value of a given URL’s component. For example, to read the URL fragment value you would use: $location.hash(), while setting the value would require an argument to be supplied to the same function: $location.hash('top').

The $location service offers other methods (not listed in the previous table) to access any part of a URL: the protocol (protocol()), the host (host()), the port (port()), and the absolute URL (absUrl()). The methods are getters only. Theycan’t be used to mutate URLs.

Hashes, navigation within a page, and $anchorScroll

The side effect of using hashbang URLs is that the part of the URL after the # sign, normally used to navigate within a loaded document, is “taken” to represent the URL part interesting from a single-page web application point of view. Still, there are cases where we need to scroll to a specified place in a document loaded into the browser. The trouble is that, in hashbang mode, URLs would contain two # signs, for example:

Browsers have no way of knowing that the second hash (#bottom) should be used to navigate within a document, and we need a little bit of help from angularjs here. This is where the $anchorScroll service comes into play.

By default the $anchorScroll service will monitor URL fragments. Upon detecting a hash that should be used to navigate within a document, it will scroll to the specified position. This process will work correctly in both the HTML5 mode (where only one hash is present in a URL) as well as in hashbang mode (where two hashes can make it into a URL). In short, the $anchorScroll service does the job which is normally performed by the browser, but taking the hashbang mode into account.

If we want to have more fine-grained control over the scrolling behavior of the $anchorScroll service you can opt out from its automatic URL fragment monitoring. To do so, you need to call the disableAutoScrolling() method on the $anchorScrollProvider service in a configuration block of a module as follows:

angular.module('myModule', [])
  .config(function ($anchorScrollProvider) {

By doing these configuration changes, we gain manual control over when scrolling takes place. We can trigger scrolling by invoking the service’s function ($anchorScroll()) at any chosen point of time.

Configuring the HTML5 mode for URLs

By default angularjs is configured to use hashbang mode for URLs. To enjoy nice-looking URLs in HTML5 mode, we need to change the default angularjs configuration, as well as set up our server to support bookmarkable URLs.

Client side

Changing to HTML5 URL mode in angularjs is trivial. It boils down to calling the html5Mode() method on $locationProvider with an appropriate argument as follows:

angular.module('location', [])
  .config(function ($locationProvider) {

Server side

For HTML5 mode to work correctly in all cases, we need a little help from the server that is responsible for serving the angularjs application files to the browser. In a nutshell, we need to set up redirections on the web server, so that requests to any deep-linking application URL will be responded with the single-page web application’s starting page (the one that contains the ng-app directive).

To understand why such redirections are needed, let’s examine a situation where a user uses a bookmarked URL (in HTML5 mode) pointing to a product backlog of a specific project. Such a URL could look as follows:

To the browser, such a URL looks like any other normal URL and the browser will issue a request to the server. Obviously such a URL only makes sense in the context of the single-page web application, at the client side. The /projects/50547faee4b023b611d2dbe9/productbacklog resource doesn’t exist physically on the server and can’t be generated by the server dynamically. The only thing that a server can do with such URLs is to redirect them to the starting point of the application. This will result in the angularjs application being loaded into the browser. When the application starts, the $location service will pick up the URL (still present in the browser’s address bar), and this is where the client-side processing can take over.

Providing further details on how to configure different servers is beyond the scope of this book, but there are some general rules that apply to all servers. Firstly, there are roughly three types of URLs that a typical web server needs to handle:

  • URLs pointing to static resources (images, CSS files, angularjs partials, and so on)
  • URLs for back-end data retrieval or modifications requests (for instance, a RESTful API)
  • URLs that represent features of the application in HTML5 mode, where the server must respond with the application’s landing page (typically a bookmarked URL used, or a URL typed in in a browser’s address bar)

Since it is cumbersome to enumerate all the URLs that can hit a web server due to the HTML5 mode links, it is probably the best to use a well-known prefix for both static resources and URLs used to manipulate data. This is a strategy employed by the sample SCRUM application where all the static resources are served from the URLs with the /static prefix, while the ones prefixed with the /databases prefix are reserved for data manipulation on a back-end. Most of the remaining URLs are redirected to the starting point of the SCRUM application (index.html).