Search code examples
angularjsnode.jsherokuexpressangularjs-ng-route

How to host an AngularJS app in Heroku using Node.js WITHOUT using yeoman?


I'm trying to push a Hello World build with AngularJS into Heroku using Node.js. BUT with multiple views(partials).

I first deployed a Hello World without using ngRoute, meaning: without partials. That was fine and smooth. Then, I tried to push 2 simple partials. But I believe the issue is hosting the application and at the same time asking for partials. I know it is not the right approach and I want your advice.

This is my index.html:

<!DOCTYPE html>
<html ng-app="main">
<head>
    <meta name="name" content="something">
    <title></title>
</head>
<body>
    <section ng-view=""></section>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular-route.min.js" type="text/javascript" charset="utf-8"></script>

    <script type="text/javascript" charset="utf-8">
    angular.module('main', ['ngRoute'])
    .config(['$routeProvider', '$http', function ($routeProvider, $http){
        console.log('hola');
        $routeProvider
        .when('/', {
            resolve: **??? I tried with templateUrl but did not work either**
            ,controller: 'indexCtrl'
        })
        .when('/second', {
            resolve: **???**
            ,controller: 'secondCtrl'
        })
        .otherwise({
            redirectTo: '/'
        });
    }])
    .controller('indexCtrl', ['$scope', function ($scope){
        $scope.helloWorld = "Hello World";
    }])
    .controller('secondCtrl', ['$scope', function ($scope){
        $scope.helloWorld = "World Hello";
    }]);
    </script>
</body>
</html>

Partial 'templates/second.html'

<h1>{{ helloWorld }}<h1>
<a href="#/" title="">Go to First</a>

Partial 'templates/index.html'

<h1>{{ helloWorld }}<h1>
<a href="#/second" title="">Go to Second</a>

My express app:

var express = require('express'),
app = express();
app.set('view engine', 'html');
app.get('/', function(req, res) {
    res.sendfile('index.html', {root: __dirname })
});
app.get('/index', function (req, res){
    res.sendfile('templates/index.html', {root: __dirname })
});
app.get('/second', function (req, res){
    res.sendfile('templates/second.html', {root: __dirname })
});
var server = app.listen(process.env.PORT || 80);

And obviously, Procfile:

web: node index.js

All the tutorials that I've found so far use Yeoman but I don't want to use Yeoman or any other scaffolding (if that is what that is) tool.

Q: Is it possible to host an AngularJS app in the same Heroku application where I'm storing the partials? If so, what am I doing wrong? If not, what is the best approach?


Solution

  • I found my issue looking at this example.

    The actual issue was that I was not making "public" the directory with express:

    app.use(express.static(__dirname));
    

    Here is the hello world

    index.html

    <!DOCTYPE html>
    <html ng-app="main">
    <head>
        <meta name="name" content="something">
        <title></title>
    </head>
    <body>
        <section ng-view=""></section>
        <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.3/angular-route.min.js" type="text/javascript" charset="utf-8"></script>
    
        <script type="text/javascript" charset="utf-8">
        angular.module('main', ['ngRoute'])
        .config(['$routeProvider', function ($routeProvider){
            console.log('hola');
            $routeProvider
            .when('/', {
                templateUrl: 'templates/index.html'
                ,controller: 'indexCtrl'
            })
            .when('/second', {
                templateUrl: 'templates/second.html'
                ,controller: 'secondCtrl'
            })
            .otherwise({
                redirectTo: '/'
            });
        }])
        .controller('indexCtrl', ['$scope', function ($scope){
            $scope.helloWorld = "Hello World";
        }])
        .controller('secondCtrl', ['$scope', function ($scope){
            $scope.helloWorld = "World Hello";
        }]);
        </script>
    </body>
    </html>
    

    Server / index.js

    var express = require('express'),
    app = express();
    
    app.use(express.static(__dirname));
    app.get('/', function(req, res) {
        res.sendfile('index.html', {root: __dirname })
    });
    var server = app.listen(process.env.PORT || 80);
    

    Procfile

    web: node index.js
    

    templates/index.html

    <h1>{{ helloWorld }}<h1>
    <a href="#/second" title="">Go to Second</a>
    

    templates/second.html

    <h1>{{ helloWorld }}<h1>
    <a href="#/" title="">Go to First</a>
    

    I hope this helps someone.

    To answer my question. Yes, it is possible, what I was doing wrong is not making the templates(files) accessible. If you want to have extra security on what can be accessible you could create a folder called, for example, public. Then make that directory static:

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

    then you can also have different routes to communicate with your application even RESTfully. Like:

    app.get('/users', function(req, res) {
        res.json({...});
    });