[angularjs] Removing the fragment identifier from AngularJS urls (# symbol)

Is it possible to remove the # symbol from angular.js URLs?

I still want to be able to use the browser's back button, etc, when I change the view and will update the URL with params, but I don't want the # symbol.

The tutorial routeProvider is declared as follows:

angular.module('phonecat', []).
  config(['$routeProvider', function($routeProvider) {
  $routeProvider.
  when('/phones', {templateUrl: 'partials/phone-list.html',   controller: PhoneListCtrl}).
  when('/phones/:phoneId', {templateUrl: 'partials/phone-detail.html', controller: PhoneDetailCtrl}).
  otherwise({redirectTo: '/phones'});
}]);

Can I edit this to have the same functionality without the #?

This question is related to angularjs url ngroute

The answer is


To remove the Hash tag for a pretty URL and also for your code to work after minification you need to structure your code like the example below:

jobApp.config(['$routeProvider','$locationProvider',
    function($routeProvider, $locationProvider) {
        $routeProvider.
            when('/', {
                templateUrl: 'views/job-list.html',
                controller: 'JobListController'
            }).
            when('/menus', {
                templateUrl: 'views/job-list.html',
                controller: 'JobListController'
            }).
            when('/menus/:id', {
                templateUrl: 'views/job-detail.html',
                controller: 'JobDetailController'
            });

         //you can include a fallback by  including .otherwise({
          //redirectTo: '/jobs'
        //});


        //check browser support
        if(window.history && window.history.pushState){
            //$locationProvider.html5Mode(true); will cause an error $location in HTML5 mode requires a  tag to be present! Unless you set baseUrl tag after head tag like so: <head> <base href="/">

         // to know more about setting base URL visit: https://docs.angularjs.org/error/$location/nobase

         // if you don't wish to set base URL then use this
         $locationProvider.html5Mode({
                 enabled: true,
                 requireBase: false
          });
        }
    }]);

Step 1: Inject the $locationProvider service into the app config's constructor

Step 2: Add code line $locationProvider.html5Mode(true) to the app config's constructor.

Step 3: in the container (landing, master, or layout) page, add html tag such as <base href="/"> inside the tag.

Step 4: remove all '#" for routing config from all anchor tags. For examples, href="#home" becomes href="home"; href="#about" becomes herf="about"; href="#contact" becomes href="contact"

 <ul class="nav navbar-nav">
     <li><a href="home">Home</a></li>
     <li><a href="about">About us</a></li>
     <li><a href="contact">Contact us</a></li>
</ul>

Start from index.html remove all # from <a href="#/aboutus">About Us</a> so it must look like <a href="/aboutus">About Us</a>.Now in head tag of index.html write <base href="/"> just after last meta tag.

Now in your routing js inject $locationProvider and write $locatonProvider.html5Mode(true); Something Like This:-

app.config(function ($routeProvider, $locationProvider) {
    $routeProvider
        .when("/home", {
            templateUrl: "Templates/home.html",
            controller: "homeController"
        })
            .when("/aboutus",{templateUrl:"Templates/aboutus.html"})
            .when("/courses", {
                templateUrl: "Templates/courses.html",
                controller: "coursesController"
            })
            .when("/students", {
                templateUrl: "Templates/students.html",
                controller: "studentsController"
            })
        $locationProvider.html5Mode(true);
    });

For more Details watch this video https://www.youtube.com/watch?v=XsRugDQaGOo


If you are in .NET stack with MVC with AngularJS, this is what you have to do to remove the '#' from url:

  1. Set up your base href in your _Layout page: <head> <base href="/"> </head>

  2. Then, add following in your angular app config : $locationProvider.html5Mode(true)

  3. Above will remove '#' from url but page refresh won't work e.g. if you are in "yoursite.com/about" page refreash will give you a 404. This is because MVC does not know about angular routing and by MVC pattern it will look for a MVC page for 'about' which does not exists in MVC routing path. Workaround for this is to send all MVC page request to a single MVC view and you can do that by adding a route that catches all

url:

routes.MapRoute(
    name: "App",
    url: "{*url}",
    defaults: new {
        controller = "Home", action = "Index"
    }
);

I write out a rule in web.config after $locationProvider.html5Mode(true) is set in app.js.

Hope, helps someone out.

  <system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
            <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
          </conditions>
          <action type="Rewrite" url="/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>

In my index.html I added this to <head>

<base href="/">

Don't forget to install url rewriter for iis on server.

Also if you use Web Api and IIS, this match url will not work out, as it will change your api calls. So add third input(third line of condition) and give out a pattern that will exclude calls from www.yourdomain.com/api


You can tweak the html5mode but that is only functional for links included in html anchors of your page and how the url looks like in the browser address bar. Attempting to request a subpage without the hashtag (with or without html5mode) from anywhere outside the page will result in a 404 error. For example, the following CURL request will result in a page not found error, irrespective of html5mode:

$ curl http://foo.bar/phones

although the following will return the root/home page:

$ curl http://foo.bar/#/phones

The reason for this is that anything after the hashtag is stripped off before the request arrives at the server. So a request for http://foo.bar/#/portfolio arrives at the server as a request for http://foo.bar. The server will respond with a 200 OK response (presumably) for http://foo.bar and the agent/client will process the rest.

So in cases that you want to share a url with others, you have no option but to include the hashtag.


According to the documentation. You can use:

$locationProvider.html5Mode(true).hashPrefix('!');

NB: If your browser does not support to HTML 5. Dont worry :D it have fallback to hashbang mode. So, you don't need to check with if(window.history && window.history.pushState){ ... } manually

For example: If you click: <a href="/other">Some URL</a>

In HTML5 Browser: angular will automatically redirect to example.com/other

In Not HTML5 Browser: angular will automatically redirect to example.com/#!/other


This answer assumes that you are using nginx as reverse proxy and you already did set $locationProvider.html5mode to true.

->For the people who might still be struggling with all cool stuff above.

Surely, @maxim grach solution works fine, but for the solution for how to respond to requests that doesn't want the hashtag to be included in the first place what can be done is check if php is sending 404 and then rewrite the url. Following is the code for nginx,

In the php location, detect 404 php error and redirect to another location,

location ~ \.php${
  ...
  fastcgi_intercept_errors on;
  error_page 404 = /redirect/$request_uri ;
}

Then rewrite url in redirect location and proxy_pass the data, offcourse, put your website url at the place of my blog's url. (Request : Question this only after you tried it)

location /redirect {
  rewrite ^/redirect/(.*) /$1;
  proxy_pass http://www.techromance.com;
}

And see the magic.

And it definitely works, atleast for me.


Be sure to check browser support for the html5 history API:

  if(window.history && window.history.pushState){
    $locationProvider.html5Mode(true);
  }

Follow 2 steps-
1. First set the $locationProvider.html5Mode(true) in your app config file.
For eg -
angular.module('test', ['ui.router']) .config(function($stateProvider, $urlRouterProvider, $locationProvider) { $locationProvider.html5Mode(true); $urlRouterProvider.otherwise('/'); });

2.Second set the <base> inside your main page.
For eg ->
<base href="/">

The $location service will automatically fallback to the hash-part method for browsers that do not support the HTML5 History API.


Just add $locationProvider In

.config(function ($routeProvider,$locationProvider)

and then add $locationProvider.hashPrefix(''); after

.otherwise({
        redirectTo: '/'
      });

That's it.


Guess this is reallllly late for this. But adding the below config to the app.module imports does the job:

RouterModule.forRoot(routes, { useHash: false })

My solution is create .htaccess and use #Sorian code.. without .htaccess I failed to remove #

RewriteEngine   On
RewriteBase     /
RewriteCond     %{REQUEST_URI} !^(/index\.php|/img|/js|/css|/robots\.txt|/favicon\.ico)
RewriteCond     %{REQUEST_FILENAME} !-f
RewriteCond     %{REQUEST_FILENAME} !-d
RewriteRule     ./index.html [L]

Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature

Examples related to url

What is the difference between URL parameters and query strings? Allow Access-Control-Allow-Origin header using HTML5 fetch API File URL "Not allowed to load local resource" in the Internet Browser Slack URL to open a channel from browser Getting absolute URLs using ASP.NET Core How do I load an HTTP URL with App Transport Security enabled in iOS 9? Adding form action in html in laravel React-router urls don't work when refreshing or writing manually URL for public Amazon S3 bucket How can I append a query parameter to an existing URL?

Examples related to ngroute

Angular 1 - get current URL parameters Removing the fragment identifier from AngularJS urls (# symbol) Redirecting to a certain route based on condition What's the most concise way to read query parameters in AngularJS? AngularJS : How do I switch views from a controller function?