Sandra Willford
Sandra Willford

Reputation: 3789

angularjs routeprovider, html5mode, and htaccess not working

I have a single page app with a router and html5mode enabled in

/account/
->index.html

The router looks like this:

app.config(function($routeProvider, $locationProvider) {
    $locationProvider.html5Mode(true);
    $routeProvider
    .when('/account', {
        templateUrl: 'account/views/welcome.html',
    }) //works
    .when('/account/emails', {
        templateUrl: 'account/views/email.html', 
        controller: 'emailController'
    }) //404 error
    .when('/account/wallet', {
        templateUrl: 'account/views/wallet.html',
    }) //404 error
    .when('/account/settings', {
        templateUrl: 'account/views/settings.html',
        controller: 'settingsController'
    }) //404 error
    .when('/account/logout', {
        templateUrl: 'account/views/logout.html',
    }) //404 error
});

Now I also have an .htaccess file in

/account/
->.htaccess

The htaccess looks like this:

RewriteEngine On  
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]  
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d  
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html  

As expected, when I go to //localhost/account/index.html or //localhost/account/ the URL is handled properly. Clicking through the navigation works correctly as well. However if I try to refresh the page at any of the routed links, or try to access them directly from the address bar, I get the Apache2 Ubuntu Default Page.

Not sure what I am doing wrong here as this seems to be pretty straight forward?

Also, if I change RewriteRule ^ /index.html to RewriteRule ^ /account/index.html instead of getting the default Apache page, I get a 404:

Not Found

The requested URL /account/index.html was not found on this server.

Upvotes: 1

Views: 1135

Answers (3)

Sandra Willford
Sandra Willford

Reputation: 3789

Turns out this solved the problem

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^(.*)$ index.html
</IfModule>

Upvotes: 0

Nico Westerdale
Nico Westerdale

Reputation: 2186

Looks like Apache is barfing on the # in the URL that angular uses for it's routes. You need something like this:

RewriteEngine on
# If an existing asset or directory is requested go to it as it is
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^(.*) /index.html [NC,L]

This is going to make it skip files and head to index.html when angular requests a file.

Upvotes: 1

Wrokar
Wrokar

Reputation: 963

I had a similar issue quite some time ago, and there are a few pieces to check.

index.html

In your index.html file's <head>, make sure that you have set the base href:

<head>
  <base href="/">
  ...
</head>

.htaccess

Your .htaccess file looks essentially like what mine looked like when I wrote it. Here is what I used (the rewrite is probably sloppy, but it worked for me!):

# Enable URL rewriting/redirecting
RewriteEngine On 
RewriteBase /

# if requested filename is not a file that exists
RewriteCond %{REQUEST_FILENAME} !-f
# AND if requested filename is not a directory that exists
RewriteCond %{REQUEST_FILENAME} !-d
# THEN rewrite the URL to be /#/PREVIOUS_URL
RewriteRule ^(.*)$ /#/$1 [L]

AngularJS Router Config

You already have the html5Mode set to true, as seen in your code:

app.config(function($routeProvider, $locationProvider) {
  $locationProvider.html5Mode(true);
  ...
});

Upvotes: 2

Related Questions