Adam Adam - 5 months ago 74
AngularJS Question

AngularJS pretty URLs does work only partialy

I have a problem with AngularJS ui-routing, for some reason the routing works only partialy when I want to use "pretty URLs", I looked up many tutorials and threads on these forums, but I just can't find any solution for this.

I have an app just like this one: https://scotch.io/tutorials/angular-routing-using-ui-router,
the only change I made is, that I added

<base href="/">
in
<head>
of index.html file.

By default it works fine, but in the url there is always hastag so the url looks like

http://ag-routing.lc/#/home


but I want it to look like this

http://ag-routing.lc/home


before you start downvoting me that this is a duplicate, here comes the problem:

On every forum I looked at, this is supposed to be the solution, paste it in your config and magic will happen.

$locationProvider.html5Mode(true);


This is how my app.js looks like with the hasbang code

// app.js
var routerApp = angular.module('routerApp', ['ui.router']);

routerApp.config(function($stateProvider, $urlRouterProvider, $locationProvider) {

$locationProvider.html5Mode(true);

$urlRouterProvider.otherwise('/home');

$stateProvider

// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
templateUrl: 'partial-home.html'
})
......


Now the # is gone, but if I refresh the page, I get a weird results or 404. So again I looked up for a solution and found out, that you have to add this code to .htaccess (source)

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]


Yay, now it works with refresh and direct links as well, but here is the real problem for which I can't find a solution:

When I hit refresh on page

http://ag-routing.lc/home


It works fine, but when I go directly (or by refresh) on page

http://ag-routing.lc/home/paragraph


it breaks, simply, second "/" will just nuke the page from orbit, it stops working and I have no idea why, the only thing I found out is, that when I open the console in chrome I get really weird results such as:

app.js:3 Uncaught SyntaxError: Unexpected token <
angular.js:3660 Uncaught Error: [$injector:modulerr] Failed to instantiate module routerApp due to:
Error: [$injector:nomod] Module 'routerApp' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.2.13/$injector/nomod?p0=routerApp
at https://code.angularjs.org/1.2.13/angular.js:78:12
at https://code.angularjs.org/1.2.13/angular.js:1531:17
at ensure (https://code.angularjs.org/1.2.13/angular.js:1456:38)
at module (https://code.angularjs.org/1.2.13/angular.js:1529:14)
at https://code.angularjs.org/1.2.13/angular.js:3632:22
at Array.forEach (native)
at forEach (https://code.angularjs.org/1.2.13/angular.js:304:11)
at loadModules (https://code.angularjs.org/1.2.13/angular.js:3626:5)
at createInjector (https://code.angularjs.org/1.2.13/angular.js:3566:11)
at doBootstrap (https://code.angularjs.org/1.2.13/angular.js:1301:20)
http://errors.angularjs.org/1.2.13/$injector/modulerr?p0=routerApp&p1=Error…trap%20(https%3A%2F%2Fcode.angularjs.org%2F1.2.13%2Fangular.js%3A1301%3A20)


and the biggest mindblown is, that when I open app.js in resources, the js code is gone and it's replaced with the HTML from index.html ಠ_ಠ

Any help appreciated and sorry for bad English...

By the way, the problem persists when I use ng-route instead of ui-route.

EDIT: I found out that when I set the locationProvider to false and hit refresh, the url turns into this thing, which seems to be wrong:

http://ag-routing.lc/about#/about

Answer

After lot of googling and putting things together, I finally stumbled upon an answer, that makes this work. The mistake I made is that I used absolute paths for my assets and links, which is wrong, you have to use relative paths, for example:

I had paths set up like this:

<!-- index.html file -->
<link href="assets/css/bootstrap.min.css" rel="stylesheet">
<script src="assets/libs/angular.min.js"></script>
<a href="about">About</a>

Notice the missing "/" at the beggining of each link, that's the catch, because, if you want to use $locationProvider.html5Mode(true) you have to set up a <base href="/"> to make it work and now you are referring to it.

Simply, to make it work you have to make sure all your links start with "/" symbol.

Like this:

<!-- index.html file -->
<link href="/assets/css/bootstrap.min.css" rel="stylesheet">
<script src="/assets/libs/angular.min.js"></script>
<a href="/about">About</a>

To make the hasbang work even with refresh on page you have to set up .htaccess properly as well.

This is how my .htaccess looks like:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews
    </IfModule>

    RewriteEngine On

    # Redirect Trailing Slashes...
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ /#!/ [L]
</IfModule>

Notice that I use "/#!/", you can set that up in angular routes where the location provider is, like this:

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