56

I'm having a massive problem with AngularJS routing.

Up until recently everything has been fine with the following route:

$routeProvider.when('/album/:albumId', {
    controller: 'albumPageController',
    templateUrl: 'views/album.html'
});

and using the href:

<a href="/#/album/{{album.id}}">Link</a>

However, now all of the slashes are being encoded into %2F.

So when I click the link, or type localhost:8000/#/album/1 into the browser, the URL is changed to:

http://localhost:8000/#%2Falbum%2F1

I've tried several things to correct this:

Using ng-href instead of href, Not using the first / (ie href="#/album/{{album.id}}") Running the app in Homestead localhost (Laravel's linux vagrant machine) instead of localhost on Windows 10

Any help would be much appreciated!

georgeawg
  • 48,608
  • 13
  • 72
  • 95
MC123
  • 845
  • 2
  • 8
  • 12
  • I've also tried using the full URL in the href (and ng-href), no changes – MC123 Dec 21 '16 at 21:43
  • are using it in html5mode? – Umer Z Dec 21 '16 at 21:45
  • 1
    $locationProvider.html5Mode({ enabled: true, requireBase: false }); – MC123 Dec 21 '16 at 21:52
  • Possible duplicate of [angularjs 1.6.0 (latest now) routes not working](http://stackoverflow.com/questions/41211875/angularjs-1-6-0-latest-now-routes-not-working) – georgeawg Dec 21 '16 at 22:06
  • Possible duplicate of [URL hash-bang (#!/) prefix instead of simple hash (#/) in Angular 1.6](http://stackoverflow.com/questions/41226122/url-hash-bang-prefix-instead-of-simple-hash-in-angular-1-6) – Mistalis Feb 24 '17 at 11:13

6 Answers6

95

%2F is the percent-encoding for the forward-slash / character.

This problem is related to the fact that AngularJS 1.6 has changed the default for hash-bang urls in the $location service.

To revert to the previous behavior:

appModule.config(['$locationProvider', function($locationProvider) {
  $locationProvider.hashPrefix('');
}]);

For more information, see SO: angularjs 1.6.0 (latest now) routes not working.

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
26

The most simple solution is to add a ! to client-side URLs (if not using HTML5 mode, which you probably do if you're here).

Client-side, update URLS like this:

#/foo/bar > #!/foo/bar

And since you keep the #, there is no issue of conflict with server-side routing. Everyone happy.

Overdrivr
  • 6,296
  • 5
  • 44
  • 70
  • Thanks! This worked for me but... what does exactly `!` does? – Francisco Romero Jun 25 '17 at 16:16
  • 5
    The `!#` (previously only `#`) is a convention defined by Angular to separate server-side routing from client-side routing. For instance, starting with this adress `foo.com/app#!/home`, if you go to URL `foo.com/app#!/profile`, you will not see a page reload. It is the Angular app (running in your browser so client-side), that will update the contents from the `home` page to the `profile` page, because you've changed the URL **after** the `#!`. Instead, if you go to `foo.com/otherstuff`, you are before the `#!` so you will request the server with the new page `otherstuff` – Overdrivr Jun 29 '17 at 07:52
10

A bit late to the party but adding a '!' to your URLs will work just fine. This bothered me for a bit as well. This is a change in the latest AngularJS 1.6.x and I read somewhere that Google requires SPAs to have that '!' after the hash. As a result my routes look as they should but my navigation makes sure I add '!' in my references. For example:

<ul>
    <li><a href="#!/">Home</a></li>
    <li><a href="#!/page2">Page 2</a></li>
    <li><a href="#!/page3">Page 3</a></li>
    <li><a href="#!/page4">Page 4</a></li>
</ul>

I hope this helps you.

Regards!

realnsleo
  • 709
  • 2
  • 12
  • 29
6

For me, i fixed the problem :

app.config(function($locationProvider) {

$locationProvider.hashPrefix('');
$locationProvider.html5Mode({
    enabled: false,
    requireBase: true
  });
});

<a href="#/mylink/"> <span>MyLink</span></a>

Which give : http://blablabla.co:8888/blabla#/mylink/

Hope this help.

Nizardinho
  • 80
  • 1
  • 4
2

slash encoding can be disabled:

$urlMatcherFactoryProvider.type('SlashFix', {
  raw:    true,
});


$stateProvider
      .state('content',{
       url: '/{slug:SlashFix}'
       ...

      })

as described here https://www.coditty.com/code/angular-ui-router-replacing-slash-with-2f-quick-fix

Igor Simic
  • 51
  • 2
0

Remove the hash symbol from the link, since you are using html5mode you do not need a hash symbol for routing

<a href="/#/album/{{album.id}}">Link</a>

becomes

<a href="/album/{{album.id}}">Link</a>
Umer Z
  • 200
  • 10
  • Just tried that - It did technically solve the issue of not encoding the slashes, but at the end of the day I need the # there (otherwise Laravel will deal with the route /album/1 and give a 404, as it's an SPA) – MC123 Dec 21 '16 at 21:57
  • Can you try with the # but set html5mode to false and requireBase to true? – Umer Z Dec 21 '16 at 22:08