MEAN Stack how does routing between express and angular work? - javascript

I'm using express static to point to public directory
//app.js
app.use(express.static( __dirname + '/public'));
how can I have it so most of the routing for UI is from AngularJS, as of now, it does not work unless on app.js I specify something like this
//app.js
app.get('/submit', function(req,res){
res.sendfile(__dirname + '/public/submit.html');
});
app.get('/schedule', function(req,res){
res.sendfile(__dirname + '/public/schedule.html');
});
if I remove the above part, and create /public/app.js instead, it does not work
// Declare app level module which depends on filters, and services
angular.module('myApp', ['page-ctrl']).
config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider.
when('/', {
templateUrl: 'index.html',
controller: LoginController
}).
when('/submit', {
templateUrl: 'submit.html',
controller: AddPostCtrl
}).
otherwise({
redirectTo: '/'
});
$locationProvider.html5Mode(true);
}]);
Simply said, what I need is to point to index.html on express, and afterward routing should be done by angular, that way I can do checking on login authentication and reroute to index page, if user not login and try to access other page.
this is what I have for app.js (express) --> /project/app.js
/*app.js*/
//dependencies
var fs = require('fs');
var http = require('http');
var https = require('https');
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
//variables
var db;
if(process.env.ENV == 'Test')
db = mongoose.connect('mongodb://localhost/videoRequestAPI_Test');
else
db = mongoose.connect('mongodb://localhost/videoRequestAPI');
var app = express();
var port = process.env.PORT || 13337;
var debug = process.env.DEBUG || false;
/**/app.use(express.static( __dirname + '/public'));/**/
/**/app.use(bodyParser.urlencoded({extended: true}));/**/
/**/app.use(bodyParser.json()); /**/
// route middleware that will happen on every request
var routes = require('./routes');
//app.get('/', routes.index);
app.get('*', function(req, res){
res.sendfile(__dirname + '/public/index.html');
});
var httpServer = http.createServer(app);
httpServer.listen(80);
console.log("Server Running! Ports 80 open for traffic");
and this is the index.html --> myproject/public/index.html
<!DOCTYPE html>
<html ng-app="page-ctrl">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="css/abc.css">
<script src="js/scripts/bootstrap.min.js"></script>
<script src="js/scripts/angular-local-storage.min.js"></script>
<script src="js/scripts/ui-bootstrap-custom-0.13.0.js"></script>
<script src="js/scripts/ui-bootstrap-custom-tpls-0.13.0.js"></script>
<script src="js/controllers/pageController.js"></script>
<script src="js/controllers/loginController.js"></script>
<script src="js/services/services.js"></script>
</head>
<body>
<nav class="navbar navbar-fixed-top" >
<aside class="col-sm-7" text-align="center">
<img src="img/sd.png" class="logo">
</aside>
<ul class="nav nav-pills">
<li role="presentation" class="nav-btn">Submit Content</li>
<li role="presentation" class="nav-btn">Scheduled Content</li>
<li role="presentation" class="nav-btn active">Pending Content</li>
</ul>
</nav>
<div class="container">
<div ng-controller="LoginController">
<input ng-model="email" type="email" class="form-control limit" placeholder="Email">
<input ng-model="credentials" type="password" class="form-control limit" placeholder="Credentials">
<button ng-click="login()" class="btn btn-primary btn-default" type="button" data-dismiss="modal">Login</button>
</div>
</div>
<footer class="footer">
© (June 2015)
</footer>
</body>
</html>

In your router.js to do all your API routes first, then a wildcard route for Angular, like this:
//API routes first
app.get('/API/users', UserController.getUsers);
app.get('/API/user/:id', UserController.getUserById);
//Then let Angular handle the rest of the routes
app.get('*', function(req,res){
return res.sendFile(__dirname + '/public/index.html');
});
The index.html being the starting point of your Angular application.
One more thing, make sure the index.html has the following in the "head" tag:
<base href="/">
EDIT:
A good starting point is to check out this great example:
https://github.com/scotch-io/starter-node-angular
and structure your application the same way:

I usually create a routes and api folder.
Each folder contains bunch of request handler functions (req, res, next). Ordered in different files based on the resource or function they serve.
Each folder has a main file (routes.js / api.js in my case) which maps all functions to the appropriate url / HTTP method. And also invokes authentication on those routes.
This allows you to very easily use different auth methods for API routes and normal routes.
If someone requires for instance a missing static asset or and undefined route, and 404 handler is invoked. So that the pages does not return the index page on all requests.
For example routes.js
module.exports = function(app) {
function ensureAuthenticated(req, res, next) {
// Authenticate....
}
function ensureAdmin(req, res, next) {
// Check for admin
}
// Resource puppies
app.all('/puppies*', ensureAuthenticated)
// Series (File Upload & Conversion)
app.get('/puppies', require('./puppie').someRoute)
// Admin*
app.all('/admin*', ensureAuthenticated, ensureAdmin)
// Admin > User
app.get('/admin/users', require('./admin').find)
app.all('/', ensureAuthenticated, ensureActive, require('./index').index)
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets|views)/*')
.get(function(req, res, next) {
var err = new Error('Resource not found: ' + req.url)
res.status(404).send(err)
})
// Index
app.all('/*', require('./index').index)
}
In app.js you can then use these routes like so
require('./routes/routes')(app)

Related

NodeJS app: error 404 for scripts/main.js when trying to link

When i go to posts index route (http://localhost:3000/posts), the main.js file served in /public/scripts folder is found, but when i go to the posts show route (...localhost:3000/posts/:id) or any other posts route, chrome's console throws an 404 error for main.js file. Apparently, it's trying to find /scripts at the /views/posts directory.
http://imgur.com/2uNAgBw
Here's my code
app.js:
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
methodOverride = require("method-override");
var postRoutes = require("./routes/posts");
app.use(bodyParser.urlencoded({extended: true}));
app.set("view engine", "ejs");
app.use(express.static(__dirname + "/public"));
app.use(methodOverride("_method"));
app.use("/posts",postRoutes);
app.listen(3000, function(){
console.log("application server is running")
});
routes/posts.js
var Post = require("../models/post");
var express = require("express");
var router = express.Router();
var middleware = require("../middleware");
//INDEX - show all colectives
router.get("/", function(req, res){
console.log("get request at /posts");
Post.find({}, function(err, allPosts){
if(err){
console.log(err);
} else {
res.render("posts/index", {posts: allPosts});
} //if
}); // Post.find
}); //router.get
//NEW - show form for creating new post
router.get("/new", middleware.isLoggedIn, function(req, res){
console.log("get request at /posts/new");
res.render("posts/new");
}); //router.get
//SHOW - show more info about a post
router.get("/:id", function(req, res){
console.log("get request at /posts/" + req.params.id);
//find the post with provided id
Post.findById(req.params.id).populate("comments").exec(function(err, foundPost){
if(err){
console.log(err);
} else {
res.render("posts/show", {post: foundPost});
} // if
}); //Post.findByID
}); //router.get
//EDIT - show edit post view
router.get("/:id/edit", middleware.checkPostOwnership, function(req, res){
console.log("get request at /posts/" + req.params.id + "/edit");
Post.findById(req.params.id, function(err, foundPost){
res.render("posts/edit", {post: foundPost});
}); //Post.findById
}); //router.get
module.exports = router;
views/posts/show.ejs
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<div id="masterContainer">
<div class="container">
...
</div>
</div>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<!-- Bootstrap's JavaScript-->
<script type="text/javascript" src="http://ricostacruz.com/jquery.transit/jquery.transit.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>
Sorry if i misused some programming terms, i'm new to web developing and not a native english speaker. Thanks ahead.
Add a / to the front of the src of your script tag.
<script src="/scripts/main.js"></script>
This way, that script tag always requests the same URL, no matter which page it's on. If you omit the leading /, the actual URL requested is relative to the current URL. For example, if you're currently at localhost:3000/foo/bar, that script tag without the leading / would send a request to /foo/scripts/main.js.
I would add a static express middleware to app.js to avoid problems like that.
app.use('/scripts', express.static(_dirname + '/path/to/scripts'));
Basically, what that does is make sure that whichever level you are on your app, express will always know where to look for the folder scripts.
You should to check the availability of the file "script/main.js".
Look to views/posts/show.ejs:
<script src="scripts/main.js"></script>
It looks like the server-side code works, but browser can't load this file on the path relative to the current route.

404 while importing external scripts angular

I am trying to include Angular module as a separate file.
Here is my app.js
var app = angular.module('app', ['ngRoute']);
app.controller("TodoController", function($scope) {
$scope.players = ["Tom", "Dick", "Harry"];
});
This is my index.html
<html ng-app="app">
<head>
<title>Hello Angular!</title>
</head>
<body ng-controller="TodoController">
<input type="text" name="" ng-model="name"> {{name}}
<ul>
<li ng-repeat="player in players">
{{ player }}
</li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular-route.min.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
I am using express with node. This is my server.js
var express = require('express');
var app = express();
var path = require('path');
var port = process.env.PORT || 5000;
app.get('/', function(req, res){
//res.sendfile('./index.html');
res.sendFile('index.html', { root: path.join(__dirname) });
});
app.listen(port);
console.log('Express app is listening on : ' + port);
When I am trying to execute I am getting http://localhost:5000/scripts/app.js 404 (Not Found)
Code is working well when everything put in to the index.html.
File Structure is like this.
-- index.html
-- server.js
-- scripts
-- app.js
I have found the solution. as mentioned on the comment issue was with Serving static files in Express. I have included this code to the server.js.
app.use(express.static('public'))
I also created the public folder and included app.js to the public folder.
My new code looks like this.
public/index.html
<html ng-app='app'>
<head>
<title>Hello Angular!</title>
</head>
<body ng-controller="TodoController">
<input type="text" name="" ng-model="name"> {{name}}
<ul>
<li ng-repeat="todo in todos">
<input type="checkbox" ng-model="todo.completed">
{{todo.title}}
</li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular-route.min.js"></script>
<script type='text/javascript' src="app.js" charset="UTF-8"></script>
<script type='text/javascript' src="app/controllers/TodoController.js" charset="UTF-8"></script>
</body>
</html>
Server.js
var express = require('express');
var app = express();
var path = require('path');
var port = process.env.PORT || 5000;
app.get('/', function(req, res){
res.sendFile('index.html', { root: path.join(__dirname, 'public') });
});
app.use(express.static(path.join(__dirname, 'public')));
app.listen(port);
console.log('Express app is listening on : ' + port);
public/controllers/TodoController.js
app.controller('TodoController', ['$scope', function ($scope) {
$scope.todos = [
{ title: 'Learn Javascript', completed: true },
{ title: 'Learn Angular.js', completed: false },
{ title: 'Love this tutorial', completed: true },
{ title: 'Learn Javascript design patterns', completed: false },
{ title: 'Build Node.js backend', completed: false },
];
}]);
public/app.js
var app = angular.module('app', []);
New file structure will be like this.
-- public
-- app
-- controllers
-- TodoController.js
-- app.js
-- index.html
-- server.js
-- package.json
Since you have only http://localhost:5000/ route which is exposed which renders index.html file.
app.get('/', function(req, res){
//res.sendfile('./index.html');
res.sendFile('index.html', { root: path.join(__dirname) });
});
Any other path will give you 404.
You cannot access http://localhost:5000/scripts/ directly.
To access scripts please add the following line in server.js
app.use(express.static(path.join(__dirname, 'scripts')));
Updated code for server.js will be.
var express = require('express');
var app = express();
var path = require('path');
var port = process.env.PORT || 5000;
app.use(express.static(path.join(__dirname, 'scripts')));
app.get('/', function(req, res){
//res.sendfile('./index.html');
res.sendFile('index.html', { root: path.join(__dirname) });
});
app.listen(port);
console.log('Express app is listening on : ' + port);
Now http://localhost:5000/scripts/app.js should not give 404.
Not just scripts/app.js, You can access any file which is in scripts folder now.

Angular : Uncaught ReferenceError: app is not defined

I am trying to create this very simple meanstack app and its almost running but with an uncaught reference error when it is redirecting to index page. Server is running ok. Browser is showing the text (Loading..) as in the index page. But as the custom tag should have gone along with the selector to app.component.ts and printed "My First Angular App", it doesn't. Instead it is saying in console that "app is not defined".
Can anyone help? I am new to MEAN & Angular, so kindly elaborate. And please excuse my silly mistakes if there are any (or many).
This is my index.html
<html>
<head>
<title>MyTaskList</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>System.import(app).catch(function(err){ console.error(err);});</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
this is my app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: 'My First Angular App'
})
export class AppComponent { }
my index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next){
res.render('index.html');
});
module.exports = router;
and finally my server.js (starting point)
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var tasks = require('./routes/tasks');
var port = 3000;
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine','ejs');
app.engine('html', require('ejs').renderFile);
app.use(express.static(path.join(__dirname, 'client')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/', index);
app.use('/api', tasks);
app.listen(port, function(){
console.log('Server started on port '+port);
});
Put app in quotes because Javascript thinks app is a variable but it should actually be a string.

Render html with node.js

I am really new to the whole MEAN-stack and are trying to create an application on openshift but are unable to render a new page.
I just keep getting this error and can't solve it with anything I've googled.
My Error: Failed to lookup view "/register" in public directory
It works completely fine to render the index page with app.get('/', func()) in server.js and tried to to the exact same thing with app.get('/register). I used to have the same problem with '/' at first but solved it using app.use(express.static(__dirname + '/public'));
Both index.html and register.html are located in the public directory.
These are extracts of my code:
index.html
<body ng-app="">
<div class="container" ng-controller="LoginController" >
<h1>Logg in</h1>
<input class="form-control" placeholder="ID"/>
<input class="form-control" placeholder="Password"/>
<button class="btn">Logga in</button>
<button ng-click="open()" class="btn">Register User</button>
</div>
</body>
logincontroller
function LoginController($scope, $http) {
console.log("Hello from Login");
$scope.open = function () {
console.log('open i login.js');
$http.get('/register')
};
};
server.js
var express = require('express');
var fs = require('fs');
var mongojs = require('mongojs');
var jade = require('jade')
var app = express();
var cors = require('cors');
var bodyParser = require('body-parser');
app.use(express.static(__dirname + '/public'));
app.use(express.bodyParser());
app.get('/env',function(req, res){
res.json(process.env);
});
app.get('/', function (req, res) {
res.render('/index', {});
});
app.get('/register', function (req, res) {
res.render('/register');
});
app.set('view engine', 'jade');
There are a couple of issues.
1) Don't use a slash for the 'register' file. This is a file in the /public folder, not a folder or route.
app.get('/register', function (req, res) {
res.render('register');
});
2) You have set jade as your rendering engine. This means you will be serving .jade files. Your public folder should have index.jade. And it should look like this:
html
body(ng-app='')
.container(ng-controller='LoginController')
h1 Logg in
input.form-control(placeholder='ID')
input.form-control(placeholder='Password')
button.btn Logga in
button.btn(ng-click='open()') Register User
A couple of notes:
Jade is a HTML templating engine, it's relatively straight forward, see http://jade-lang.com/tutorial/.
There is express-generator which will give you an example app, it's an excellent starting point: http://expressjs.com/en/starter/generator.html
By the way, there is also an HTML-2-Jade converter, I find this helpful sometimes: http://html2jade.org/

Configuring Express and Angular

I'm trying to make a simple Angular/Express todo-list app, and I ran into quite a bit of trouble. It's still in the works, but when I ran the code below on localhost:3000 I ended up getting {{ thing }} literally printed in the webpage.
My file paths are:
app
js
app.js
index.html
node_modules (here lies angular, express, etc)
index.js
package.json
Here is my code for index.html:
<!DOCTYPE html>
<html lang="en" ng-app='testApp'>
<head>
<meta charset="UTF-8">
<title>Angular-Express Test App</title>
<script type='text/javascript' src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.12/angular.min.js"></script>
<script type='text/javascript' src='js/app.js'></script>
</head>
<body ng-controller='TestCtrl'>
<table>
<thead>
<tr>
<td>Item</td>
<td>Remove</td>
</tr>
</thead>
<tbody>
<tr ng-repeat='item in items'>
<td>{{ item }}</td>
<td>Done?</td>
</tr>
</tbody>
</table>
</body>
</html>
Here is my code for index.js:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser');
var jsonParser = bodyParser.json();
var urlencodedParser = bodyParser.urlencoded({ extended: false });
app.set('port', process.env.OPENSHIFT_NODEJS_PORT || 3000); //yes I plan to deploy to OpenShift
app.set('ipaddr', process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1");
app.get('*', function(req, res){
res.sendFile(__dirname + '/app/index.html', res);
});
http.listen(3000, function () {
'use strict';
console.log('Express server listening on IP: ' + app.get('ipaddr') + ' and port ' + app.get('port'));
});
And app.js:
angular.module('testApp', ['ngRoute'])
.controller('TestCtrl', [$scope, function ($scope) {
'use strict';
$scope.items = ["foo", "bar"];
}]);
Here's a screenshot of what I see, though there really isn't much in it that I haven't mentioned already...: http://puu.sh/gyhjT/684fa116f7.png
I spent a ridiculous amount of time trying to figure out what went wrong, so any help at all would be greatly appreciated!
there are few mistakes in your code,
first , the major one, you are directing every request to index page, so no way to get js/app.js
so change:
app.get('*', function(req, res){
res.sendFile(__dirname + '/app/index.html', res);
});
to:
app.get('/', function(req, res){
res.sendFile(__dirname + '/app/index.html', res);
});
app.get('/js/:file', function(req, res){
res.sendFile(__dirname + '/app/js/'+req.params.file, res);
});
next is, ngRoute and $scope mistake, ngRoute is not part of angular.min.js, you have to include it seperately, for now, i just changed your js/app.js and it works for me
angular.module('testApp', [])
.controller('TestCtrl', ['$scope', function ($scope) {
'use strict';
$scope.items = ["foo", "bar"];
}]);
remove ['ngRoute'] because you don't use it. If you want to use, please include angular-route.js in head

Categories