AngularJs remove # (hash) from url or setup Pretty URL

This article will help you to setup Pretty URL in AngularJs, that is to remove # from url.

AngularJS applications by default route with # in the url, the reason for the same is that # is an old browser shortcut which doesn't fire the request.This allows many JavaScript frameworks to build their own client side rerouting.

We need the # (hashtag) for non HTML5 browsers, otherwise they will just do an HTTP call to the server at the mentioned href.


Url with #
http://example-domain.com/#/home  
Url without #
http://example-domain.com/home  


Getting Started

For now let's hope you have already setup a new AngularJs project or has an existing AngularJs project.Here we are considering working with an existing AngularJs App. I have named my project as angular-one-sample.

The project was scaffolded using Yeoman gulp-angular generator , Yeoman is scaffolding tool for modern web apps and can be used to generate basic app structure for your projects.



project-setup-angularjs-yeoman

After generating the basic app using Yeoman the project structure looks something like this


project-structure-angularjs

if you want to run the same in local just use the command

gulp serve --open  

The above command will start serving the project at the url

http://localhost:3000/#/home  



gulp-serve-angularjs


To remove #

To remove the # from URL we need to make sure 4 things mainly.

  • Configure the $locationProvider
  • Setting our base for relativelinks
  • Edit your .htaccess file if you are using apache server
  • Remove # from the routing links through out the app (optional)


Configure $locationProvider

Angularjs $location service parses the URL in the address bar and makes changes to your application and vice versa.

We will use the $locationProvider module and set html5Mode to true.

Now import the $locationProvider module to the router file index.route.js and add the following code to enable the html5Mode

 // use the HTML5 History API
 $locationProvider.html5Mode(true);

html5Mode is a standardized way to manipulate the browser history using a script. This lets Angularjs change the routing and URLs of our pages without refreshing the page.

After editing the router file it will look something like this


index.route.js

(function() {
  'use strict';

  angular
    .module('angularOneSample')
    .config(routerConfig);

  /** @ngInject */
  function routerConfig($stateProvider, $urlRouterProvider,$locationProvider) {
    $stateProvider
      .state('home', {
        url: '/home',
        templateUrl: 'app/main/main.html',
        controller: 'MainController',
        controllerAs: 'main'
      });


    // use the HTML5 History API
    $locationProvider.html5Mode(true)
    $urlRouterProvider.otherwise('/');
  }

})();


Setting our Base

To link around your application using relative links, you will need to set a <base> in the <head> of your document. while setting base you will have to consider where the projects resides in the server

if your project files is placed in the /var/www/html folder (that is project files copied from dist folder after gulp build to root folder of your server) or you are running on gulp serve (while under development in local) then your base will be

<base href="/">  

if your project files resides in some folder somefolder then set base to

<base href="/somefolder/">  

In my case while developing (on gulp serve) in local i had to set base to

<base href="/">  



index.html

<!doctype html>  
<html>  
<head>  
    <meta charset="utf-8">
    <base href="/">
</head>  

Now you can see that the app reloads and # is removed from url

local-gulp-serve-hash-removed

Edit your .htaccess file

Sometimes while While running on the Apache server Angulajs Apps seems to hit 404 Page Not found error on page refresh. To solve this issue we need to add the .htaccess file with the following code to the project folder/root folder where project files are placed

 RewriteEngine on

# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]  
RewriteCond %{REQUEST_FILENAME} -d  
RewriteRule ^ - [L]

# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]  

Also since we are enabling pretty url to increase SEO points, i like to add some more code to .htaccess to enable compression and leverage browser Caching

RewriteEngine on

# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]  
RewriteCond %{REQUEST_FILENAME} -d  
RewriteRule ^ - [L]

# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.html [L]


# Enable Compression
<IfModule mod_deflate.c>  
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
  AddOutputFilterByType DEFLATE application/x-font
  AddOutputFilterByType DEFLATE application/x-font-opentype
  AddOutputFilterByType DEFLATE application/x-font-otf
  AddOutputFilterByType DEFLATE application/x-font-truetype
  AddOutputFilterByType DEFLATE application/x-font-ttf
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE font/opentype
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain
</IfModule>  
<IfModule mod_gzip.c>  
  mod_gzip_on Yes
  mod_gzip_dechunk Yes
  mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
  mod_gzip_item_include handler ^cgi-script$
  mod_gzip_item_include mime ^text/.*
  mod_gzip_item_include mime ^application/x-javascript.*
  mod_gzip_item_exclude mime ^image/.*
  mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>

# Leverage Browser Caching
<IfModule mod_expires.c>  
  ExpiresActive On
  ExpiresByType image/jpg "access 1 year"
  ExpiresByType image/jpeg "access 1 year"
  ExpiresByType image/gif "access 1 year"
  ExpiresByType image/png "access 1 year"
  ExpiresByType text/css "access 1 month"
  ExpiresByType text/html "access 1 month"
  ExpiresByType application/pdf "access 1 month"
  ExpiresByType text/x-javascript "access 1 month"
  ExpiresByType application/x-shockwave-flash "access 1 month"
  ExpiresByType image/x-icon "access 1 year"
  ExpiresDefault "access 1 month"
</IfModule>  
<IfModule mod_headers.c>  
  <filesmatch "\.(ico|flv|jpg|jpeg|png|gif|css|swf)$">
  Header set Cache-Control "max-age=2678400, public"
  </filesmatch>
  <filesmatch "\.(html|htm)$">
  Header set Cache-Control "max-age=7200, private, must-revalidate"
  </filesmatch>
  <filesmatch "\.(pdf)$">
  Header set Cache-Control "max-age=86400, public"
  </filesmatch>
  <filesmatch "\.(js)$">
  Header set Cache-Control "max-age=2678400, private"
  </filesmatch>
</IfModule>  


Remove # from links used in the app

This step is optional, even if the # in navigation links were not removed, the links will work without any problem . These links automatically will be redirected to links without # (hash)



hash-removed-url