Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: Relative link paths are broken when html5mode(true) is on

I've been searching and I've found "solutions" to this problem, yet I still can't get this to work right.

The Scenario:

I'm building an Angular (version 1.2) website with the UI Router and running it on a Node server on localhost. I'm trying to make it have "pretty" url's with the $locationProvider and by turning html5(true) on. My website works fine when clicking through it, but when I try to navigate to a relative link path or refresh the link path the page breaks. I also intend to deploy this webapp to Heroku when completed:

RELATIVE LINK PATH:

http://localhost:8000/locksmith-services

PAGE OUTPUT RESULT

Cannot GET /locksmith-services


Steps I've taken:

1.) In my "index.html" < head >, I've set my base url to:

<base href="/"></base>

2.) In my app.js file (for Angular), I have it written as follows:

// App Starts
angular
    .module('app', [
        'ui.router',
        'ngAnimate',
        'angular-carousel'
    ])
    .config(['$urlRouterProvider', '$stateProvider', '$locationProvider', function($urlRouterProvider, $stateProvider, $locationProvider) {
        $urlRouterProvider.otherwise("/");

        $stateProvider
            .state('home', {
                url: '/',
                templateUrl: 'pages/home.html',
                controller: 'homeCtrl'
            })
            .state('services', {
                url: '/locksmith-services',
                templateUrl: 'pages/locksmith-services.html',
                controller: 'servicesCtrl'
            })
            .state('locations', {
                url: '/locksmith-locations',
                templateUrl: 'pages/locksmith-locations.html'
            })
            .state('payment', {
                url: '/locksmith-payment',
                templateUrl: 'pages/locksmith-payment.html'
            })
        // use the HTML5 History API
        $locationProvider.html5Mode(true);
    }])

3.) In my navigation, I have my html written as:

<div class="wrapper">
    <a ui-sref="home">
        <img src="images/logo.png" class="logo" alt="Austin Texas Locksmith" />
    </a>
</div>
<nav class="row navigation">
    <a class="mobile33" ui-sref="services" ui-sref-active="active" class="active">Services</a>
    <a class="mobile33" ui-sref="locations" ui-sref-active="active">Locations</a>
    <a class="mobile33" ui-sref="payment" ui-sref-active="active">Payment</a>
</nav>

4.) My server.js file (node server)

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/front'));
var port = process.env.PORT || 8000;
app.listen(port);

What would be the best solution? Thanks in advance for your help.

like image 591
Oneezy Avatar asked Sep 26 '14 19:09

Oneezy


People also ask

What is html5Mode in Angularjs?

html5Mode specifies, we catch all urls on the server, similar to the otherwise route in angular, and return the same html as the root domain. But if I then check the $location object from within the run function of angular, it tells me that http://www.site.com is my host and that /archive is my path .

What is html5Mode?

In HTML5 mode, the $location service getters and setters interact with the browser URL address through the HTML5 history API. This allows for use of regular URL path and search segments, instead of their hashbang equivalents.


2 Answers

Thanks to @trehyu for helping me get to this answer.

Like he wrote, I needed something setup on my server.js file that redirects the user to my "index.html" file.

So depending on your file structure...

BEFORE (not working)

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/front'));
var port = process.env.PORT || 8000;
app.listen(port);

AFTER (working)

var express = require('express');
var app = express();

app.use('/js', express.static(__dirname + '/front/js'));
app.use('/build', express.static(__dirname + '/../build'));
app.use('/css', express.static(__dirname + '/front/css'));
app.use('/images', express.static(__dirname + '/front/images'));
app.use('/pages', express.static(__dirname + '/front/pages'));

app.all('/*', function(req, res, next) {
    // Just send the index.html for other files to support HTML5Mode
    res.sendFile('/front/index.html', { root: __dirname });
});

var port = process.env.PORT || 8000;
app.listen(port);

I hope this helps someone else!

like image 66
Oneezy Avatar answered Sep 27 '22 21:09

Oneezy


When HTML5mode is set to true, you need something setup on your server that automatically redirects the user to your index page, so that the AngularJS UI Router can take over from there.

The reason for this is that without the hash (#) in the URL, it takes it as a literal URL and tries to navigate there when you refresh or paste the url directly.

I'm not very familiar with Node so not sure how you would do that, but there is a FAQ page on the UI Router GitHub that should help you get started: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode

like image 22
Kari Avatar answered Sep 27 '22 20:09

Kari