5

I have a following AngularJS app:

angular.module('app', ['ngRoute', 'app.controllers'])
.config(['$routeProvider', function($routeProvider){
    $routeProvider
        .when('/', {
            controller: 'HomeController',
            templateUrl: 'views/home.html'
        })
        .when('/garage', {
            controller: 'GarageController',
            templateUrl: 'views/vehicle.html'
        })
        .otherwise({
            redirectTo: '/'
        });
}])
.config(['$locationProvider', function($locationProvider) {
    $locationProvider.html5Mode(true);
}]);

Node.js is my backend and its only purpose is to provide REST api (which is not implemented yet). Express configuration is as follows:

app.use(express.static(path.join(__dirname, 'public')));

app.get('*', function(req, res) {
   res.sendFile(__dirname + '/public/index.html');
});

The problem is that whenever I put some invalid url in the address bar, like http://localhost:3000/abc request reaches the server. I assumed, that it should be handled by AngularJS routing and redirected to default '/' page. Why is that not happening? When that happens, all aplication is downloaded once again, all index and assets files. I would like to tell AngularJS - whenever somebody enters an invalid route, just route to the default one. And this should just replace ng-view, rather than downloading whole index.html once again. Is that possible?

Thanks

5
  • Nobody can help me here? Commented Nov 23, 2014 at 6:44
  • I have the same problem, did you ever figure out what the problem was:) Commented Feb 18, 2015 at 15:25
  • Unfortunately not :( Commented Mar 19, 2015 at 7:33
  • I wonder if this is because you need to have two routings? I.E. you need your angular routing to only pick up calls to it self, otherwise you would have issues doing api calls for example (i.e. lets say you have www.../api/getdata and www.../api/savedata you would need a way for angular to know that is should answer to /, /garage, any other combination but not /api/.... Could be wrong though Commented Mar 20, 2015 at 9:09
  • my biggest problem is that otherwise in Angular routin seems not to work at all but instead request to the server is made Commented Mar 21, 2015 at 8:15

2 Answers 2

0

Not certain if this helps, but this routing works quite well. (app.js)

var routes = require('./routes/index');
var users = require('./routes/users');
var api = require('./routes/api')
var partials = require('./routes/partials')

Then on the other end the following code to get angular routes up an running:

    var BabyPadz = angular.module('BabyPadz', ["ngResource", "ngRoute"]).
    config(['$routeProvider', '$locationProvider',
        function ($routeProvider, $locationProvider) {
            $locationProvider.html5Mode(true);
            $routeProvider
                .when('/', {
                    templateUrl: 'partials/index',
                    controller: 'IndexController'
                })
                .when('/about', {
                    templateUrl: '/partials/about',
                    controller: 'AboutController'
                })
                .when('/contactus', {
                    templateUrl: "partials/contactus",
                    controller: 'ContactController'
                })
                .when('/boompad', {
                    templateUrl: "partials/boompad",
                    controller: "BoomController"
                })

                // route for the about page

                .otherwise({redirectTo: "/test"});
        }
    ]
);

I realised I use ngResource as well, know that there was something that changed a year or two ago, something about the split of angular (so Route and so forth is a separate module). Not certain if that is the case.

I still get a 404 at times, but think that is the server end to allow Angular to pick up the routing, but have not been able to get a completely answer to that question how routing (server/angular) works together or what gets priority.

Sign up to request clarification or add additional context in comments.

4 Comments

And when you type /aaaa in the browser you are redirected to /test?
Yes, if I put anything (including /aaaa) it redirects nicely.
this is weird because my config looks pretty the same but when requested /aaaa request is sent to the server and browser downloads index.html. What browser do you use?
I use chrome. If it's anything like the issues I had, the problem could be in your server routes. Does the other routes work?
0

I was having the exact same problem you were having, and have 2 possible solutions for you!

//////////////////////////////

Solution #1: List the directories you do/don't want "served"

//////////////////////////////

How to:

Let's say your directory structure is like this:

-app/
---controllers/
---directives/
---etc.
-public/
---img/
---css/
---index.html
---etc.
-views/
---home.html
---vehicle.html
---etc.
-app.js (run with 'node app.js')

Some of these 3 folders (app,public,views) have different rules on which you want to serve and which you want to render:

  • app/
    • serve: If your site does GET /app/controller.js, you want to serve them the literal file.
  • public/
    • serve: If your site does GET /public/img/logo.jpg, you want to serve them the literal file.
  • views/
    • render: If your site does GET views/home, you want to render them the view from your angular.js route.

Now from your node/express js file, locate or add the following:

//This tells node that these folders are for STATIC SERVING files (meaning literal files). 
//And Yes! You can use multiple to indicate multiple directories.
app.use(express.static(path.join(__dirname, 'app')));
app.use(express.static(path.join(__dirname, 'public')));

More Info:

app.use(express.static(__dirname + '/client/views')); means you are serving literal files from /client/views but nothing OUTSIDE of that directory. See angularjs index.html in views folder

Expanded Example:

This would be your possible configuration:

//app.js

var express = require('express'),
  bodyParser = require('body-parser'),
  methodOverride = require('method-override'),
  errorHandler = require('error-handler'),
  morgan = require('morgan'),
  routes = require('./routes/index'), //My special routes file
  http = require('http'),
  path = require('path');

var app = module.exports = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(morgan('dev'));
app.use(bodyParser());
app.use(methodOverride());
app.use(express.static(path.join(__dirname, 'app')));
app.use(express.static(path.join(__dirname, 'public')));

// serve index and view partials
app.get('/', routes.index);

//Partials
app.get('/partials/:name', routes.partials);

// redirect all others to the index
// BUT the static files listed above still get served statically
app.get('*', routes.index);

http.createServer(app).listen(app.get('port'), function () {
  console.log('Express server listening on port ' + app.get('port'));
});

Then this would be your routes file:

exports.index = function(req, res){
  res.render('index');
};

exports.partials = function (req, res) {
  var name = req.params.name;
  res.render('partials/' + name);
};

//////////////////////////////

Solution #2: Check if the file exists first

//////////////////////////////

How to:

Keep everything how you already have it, but instead of trying "res.sendFile" immediately, check if it exists first. For example:

exports.all = function (req, res) {
    var name = req.params[0];
    fs.exists(path+'/'+name, function(exists){
        if(exists)
        {
                //console.log("file exists");
                res.sendFile(path+'/'+name);
        }else{
                //console.log("file does not exist");
                //redirects to index
                res.render('index');
        }
    });
};

Expanded Example:

This would be your possible configuration:

//app.js

var express = require('express'),
  bodyParser = require('body-parser'),
  methodOverride = require('method-override'),
  errorHandler = require('error-handler'),
  morgan = require('morgan'),
  routes = require('./routes/index'), //My special routes file
  http = require('http'),
  path = require('path');

var app = module.exports = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(morgan('dev'));
app.use(bodyParser());
app.use(methodOverride());
app.use(express.static(path.join(__dirname, '')));

// serve index and view partials
app.get('/', routes.index);

//Partials
app.get('/partials/:name', routes.partials);

// redirect all others
app.get('*', routes.all);

http.createServer(app).listen(app.get('port'), function () {
  console.log('Express server listening on port ' + app.get('port'));
});

and this is your routes file:

var fs = require('fs');
var path = require('path');

exports.index = function(req, res){
  res.render('index');
};

exports.partials = function (req, res) {
  var name = req.params.name;
  res.render('partials/' + name);
};

exports.all = function (req, res) {
    var name = req.params[0];
    fs.exists(path+'/'+name, function(exists){
        if(exists)
        {
                //console.log("file exists");
                res.sendFile(path+'/'+name);
        }else{
                //console.log("file does not exist");
                //redirects to index
                res.render('index');
        }
    });
};

//////////////////////////////

Hope that helps!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.