4

i have posted a question on stackoverflow (css and javascript didn't include on refresh) yesterday asking the question about why the css and javascript didn't include on my webpage after I refresh the webpage and found out it caused by the html5mode, so i have been searching the solution for this problem since yesterday but I can't really get an answer.

my folder structure

enter image description here

app.js

var express = require('express')
  , routes = require('./routes')
  , user = require('./routes/user')
  , http = require('http')
  , path = require('path')
  , mongoose = require('mongoose');

var app = module.exports=express();
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/public/views');
app.set('view engine', 'ejs');
app.use(express.cookieParser());
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(path.join(__dirname, 'public')));
app.use(app.router);
app.use(function(request, response)
{
    console.log("catch all");
    writeFile("/public/views/master.ejs", request, response);
});
// development only
if ('development' == app.get('env')) {
  app.use(express.errorHandler());
}
app.use(function (req,res) {
 res.status(404).render('error', {
                url: req.originalUrl
            });
});

app.get('/', routes.index);
app.get('/:name', routes.view);
app.get('*', routes.risk);

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

index.js

exports.index = function(req, res){
  res.render('master', { title: 'Hello World' });
};
exports.view = function (req, res) {
  var name = req.params.name;
  res.render(name);
};
exports.risk = function(req, res){
  res.sendfile(__dirname + "/public/views/master.ejs");
};

for the exports.risk i was trying to make the expressJs to render the master page 1st before it renders other but it doesn't work.

angularJs

var SymSal = angular.module('SymSal',[]).
 config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
    $routeProvider.
      when('/', {
        templateUrl: 'main.ejs',
        controller: 'IndexCtrl'
      }).
      when('/login',{
        templateUrl: 'login.ejs',
        controller: 'IndexCtrl'
      }).
      when('/register',{
        templateUrl: 'register.ejs',
        controller: 'IndexCtrl'
      }).
      when('/about',{
        templateUrl: 'about.ejs',
        controller: 'IndexCtrl'
      }).
      otherwise({
        templateUrl: 'error.ejs'

      });
    $locationProvider.html5Mode(true);
  }]);

 SymSal.controller('IndexCtrl',function(){

 })

Your help is appreciated, THANK YOU !!

1

2 Answers 2

5

for the exports.risk i was trying to make the expressJs to render the master page 1st before it renders other but it doesn't work.

Routes are matched in sequential order:

app.get('/', routes.index);
app.get('/:name', routes.view);
app.get('*', routes.risk);

If the route matches '/' render routes.index. If the route doesn't match '/' check if it matches '/:name' (e.g. /login, /register) and render routes.view. If the route doesn't match '/' and '/:name' (e.g. route is something like /user/1) routes.risk will be rendered.

To make express render the master page first you need to remove the route matcher for '/' and '/:name' and keep the universal matcher ('*') that will match every route.

Now the server will send back the master page no matter what url you provide. If you call localhost:3000/login the server will send back the master page (same page as is if you would call localhost:3000). Angular will see that a path (/login) is specified and will call the appropriate $routeProvider.when() function.

To handle api calls (like get data from db, save data to db) you need to specify a route matcher for this and place it above the universal matcher ('*'):

app.get('/api', routes.api);

It's important to mention that you don't use '/api' in your $routeProvider.when().

What's left is the correct handling of static files: Remember every url is handled by the universal matcher ('*'). So static files get render with the wrong MIME type. To fix this, you need to make all static files accessible under a specific path e.g '/static'. Simply update

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

to

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

You need to update all paths in your master page to match the new pattern: '/js/angular.js' is now '/static/js/angular.js'

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

7 Comments

hey bekite thanks for the reply !, i have tried your solution but my angular.js seems to have some error on it , when i start my app the webpage all hanging there and keep loading may i know what causes this problem ?
I've created a plunker: plnkr.co/edit/V8OWrMrnXM3j76WZ4TVc?p=catalogue . This should render an html page. I'm using jade templating and you use ejs. So you need to edit the views/index.jade.
Sorry, didn't know where to start. It looks to me that you haven't update your templateUrl: 'main.ejs' to match the new path. Angularjs crashes when it can't find the template. I think thats the reason your app crashes.
thank you !! if you're around my country i will totally buy you a beer ^_^
I'm glad I could help and save you some hours. Took me days to get it running.
|
2

Thanks to @bekite for the basis of a plausible solution. Building on his initial solution, I've found the following a little cleaner for myself, and it avoids needing to update and maintain all your paths with a /static prefix. Note that the app.get('*', routes.risk) did not work for me (Express v3.4.4), however using a regex did:

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

// Express routes - ensure these are not defined in Angular's app.js $routeProvider:
app.get('/api', routes.api);

/**
 * ANGULAR APP ROUTING
 * --------------------
 * These routes will fallback to Angular for resolution of any uri:
 * Note that the * wildcard will not work, hence the alternate regex
 * It is crucial that 'static' assets never be referenced with a leading
 * forward slash '/', else they'll match this rule and 404's will occur
 */
//app.get('*', routes.risk);
app.get('/[a-z]{0,100}', routes.risk);

////
// alternatively:
//
// app.get('/[a-z]{0,100}', function(req, res) {
//     res.sendfile('app/index.html', {title: 'Default Title', stuff: 'More stuff to send to angular'}
// });
...

As per @bekite, Angular paths are passed through to a generic route (which may provide further branching if desired), and captured by the Angular $routeProvider. Express paths are caught with the /api prefix and processed server-side as needed.

1 Comment

I had the same problem with app.get('/*' but when I changed to app.get('/[a-z0-9\/]{0,100}', it worked as expected. Did you understand why it's like this?

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.