15

I've got in impasse with setting Angular routes to work with Express.

I tried to do like here Express 4, NodeJS, AngularJS routing but that did not work. The static index.html serves each time the url changes, but the Angular does not catch the partial.

In my Express I have the following code:

var express = require("express");
var app = express();
app.use(express.static(__dirname + '/app'));
app.use("*",function(req,res){
    res.sendFile(path.join(__dirname,"app/index.html"));
});
app.listen(1337, function(){
    console.log("Server is listening on port 1337");
});

And in my Angular app, I have the following:

var app = angular.module("myapp",["ngRoute","appControllers"]);

    app.config(["$routeProvider","$locationProvider",function($routeProvider,$locationProvider){
            $locationProvider.html5Mode(true);
            $routeProvider
                    .when("/list",{
                        templateUrl: "/partials/users.html",
                        controller: "userListCntr"
            })
                    .when("/edit", {
                        templateUrl: "/partials/edit.html",
                        controller: "userEditCntr"
            })
                    .when("/register", {
                        templateUrl: "/partials/register.html",
                        controller: "registerCntr"
            })
                    .when("/login", {
                        templateUrl: "/partials/login.html",
                        controller: "registerCntr"
            });

    }]);

I don't have any errors in my browser console. The html inspector shows: <!-- ngView: --> so the directive is kind of initialized.

And dependency list:

dependencies": {
    "angular": "1.3.x",
    "angular-mocks": "1.3.x",
    "jquery": "1.10.2",
    "bootstrap": "~3.1.1",
    "angular-route": "1.3.x",
    "angular-resource": "1.3.x",
    "angular-animate": "1.3.x"
  }

here is my file structure:

--app (angular app)
   --components
   --js
   --css
   --img
   --assets
   --partials
   --index.html
--node-modules
--server.js (here express settigs are)

ALso, I made changes as follows to account for all static resources, but still does not work:

app.use(express.static(__dirname+ "/app"));
app.use('/js', express.static(__dirname + '/app/js'));
app.use('/dist', express.static(__dirname + '/../dist'));
app.use('/css', express.static(__dirname + '/app/css'));
app.use('/assets', express.static(__dirname + '/app/assets'));
app.use('/components', express.static(__dirname + '/app/components'));
app.use('/img', express.static(__dirname + '/app/img'));
app.use('/partials', express.static(__dirname + '/app/partials'));

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

Please, help, because I can't find a solution. Thanks!

Community
  • 1
  • 1
kirgol
  • 367
  • 1
  • 3
  • 12

5 Answers5

9

When you don't pass a path to express.use(), then it defaults to /. The proceeding rule you set for * is either redundant or may not even work.

Also, since you're using html5mode, you need to explicitly set apart routes from resources so Express doesn't try to serve up your index.html file for all requests.

Try this example from Angular UI-Router on for size:

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

app.use('/js', express.static(__dirname + '/js'));
app.use('/dist', express.static(__dirname + '/../dist'));
app.use('/css', express.static(__dirname + '/css'));
app.use('/partials', express.static(__dirname + '/partials'));

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

app.listen(3006); //the port you want to use
  • Thanks, but that did not work. Still no GET requests and renderning of partials. I have my angular app in /app folder, so i changed your answer like this app.use(express.static(__dirname+ "/app")); app.use('/js', express.static(__dirname + '/app/js')); app.use('/dist', express.static(__dirname + '/../dist')); app.use('/css', express.static(__dirname + '/app/css')); app.use('/partials', express.static(__dirname + '/app/partials')); – kirgol May 30 '15 at 13:58
  • Can you update your question with your file structure? Also, are you serving static partials or serving them via $templateCache? – joshuahiggins May 30 '15 at 14:00
  • I have static html partials. Thank for your help, I updated the question with file structure – kirgol May 30 '15 at 14:09
  • Sorry, please, see my file structure (i forgot to add code tags to it) – kirgol May 30 '15 at 14:16
  • It's been a minute since I've used Express. I see they changed the API around for version 4 and the example that UI-Router has uses version 3 syntax. I assume you're on 4? – joshuahiggins May 30 '15 at 14:29
  • Yes, I am on 4. SHould I change the syntax for that. The thing is that I am learning Express only 4 days. Too much info to consume. Please, help – kirgol May 30 '15 at 14:43
  • I looked over the migration guide and I was wrong... `.use()` changed some, but not in a manner that impacts this example. Unfortunately I can't replicate your issue. I just spun up a new app that follows your app structure and even copy and pasted your server block using both Express 3 and Express 4 and they both worked. – joshuahiggins May 30 '15 at 15:15
  • Joshua, thank you very much for your efforts. I just found that I should add to the head in my index.html. Found here: http://stackoverflow.com/questions/18214835/angularjs-how-to-enable-locationprovider-html5mode-with-deeplinking. And it worked suprisingly. The Angular grasped the partial at last!) – kirgol May 30 '15 at 15:24
  • By the way, may it be something to do witn angular version. What version did you use? – kirgol May 30 '15 at 15:29
  • 1.3 and 1.4. The base issue makes sense. I just assumed it wasn't that since you didn't mention any console errors, which Angular throws when you use html5mode without a base. – joshuahiggins May 30 '15 at 15:30
2

Thanks everybody for help. I resolved the question by inserting <base href="/" /> into head section of my Angular index.html. It worked for me, but as of now it's like magic and cargo coding, since I don't understand why it works :) Found solution here: AngularJS: how to enable $locationProvider.html5Mode with deeplinking

Community
  • 1
  • 1
kirgol
  • 367
  • 1
  • 3
  • 12
1

I just want to add that adding base href= helped me. I have my app statically served in express and browsing directly to routes in my angular app would cause lots of

refused to execute script because its mime type ('text/html') is not executable and strict mime type checking is enabled

errors to be throw. But adding base href fixed that and I can browse directly to my angular routes now.

Martin Zabel
  • 3,589
  • 3
  • 19
  • 34
0

While the solution suggested by @kirgol of using base href= works fine, there is an alternative solution which might interest someone looking for simple route serve. In this solution we will not using ExpressJS routing

Simply use this

app.use(express.static(__dirname + '/app'));

instead of this

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

This way expressJS will automatically serve the index.html present at that static location & will handle the routing automatically. It will behave just like a simple http server. The moment you handle the routing using app.all/ app.get - you will have to set base href to tell $locationProvider of location from which it can match routes

rahulthakur319
  • 455
  • 4
  • 16
0

I too faced a similar situation for routing through angular components using express, this is how I was able to resolve the routing issue:

Setup for my Nodejs Project:

  • Build an Angular Project for production and placed in the public folder.
  • Created an app.js file for the express server with the following contents:

    var express = require('express'); var app = require('express')(); const port = 8090; app.use(express.static('public')); app.listen(port,()=>{console.log("App working at port : http://localhost:"+port)});

Running this loaded the Root Component only, from where I had to manually route through different pages using routerLink. If I instead tried to give the child components directly using URL I got a Cannot GET/{URL} error.

Fix:

  • I added the express-http-proxy package imported as
  • var proxy = require('express-http-proxy');
  • Then added in the following line after the app.use(express.static('public'));
  • app.use('/*',proxy('http://localhost:'+port+'/*'));

This fixed my issue.Apparently there is a more standard fix Refer Link