I'm using Node & Express on the server side, and Angular on the client side.
But I can't implement Angular Client-Side routing. My Angular router looks like this:
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/blogs', {
templateUrl: 'partials/blogs',
controller: 'BlogController'
}).
when('/news', {
templateUrl: 'partials/news',
controller: 'NewsController'
}).
otherwise({redirectTo: '/'});
}]);
This is my server routes:
app.use('/',routes.index);
app.use('/partials/:filename',routes.partials);
And my index.js:
exports.partials = function(req, res){
var filename = req.params.filename;
if(!filename) return;
res.render("partials/" + filename );
};
exports.index = function(req, res){
res.render('index');
};
But instead of presenting the partials, I get the index page for every URL
What am I doing wrong?
You have to create a route like this:
router.get('*', function(req, res){
res.render('layout');
});
In layout.jade you can initialize your routes:
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js')
script(src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.5/angular-route.js')
script(src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.7/angular-resource.min.js')
script(src='/javascripts/app.js')
App.js:
var app = angular.module('app', ["ngRoute"]);
app.config(['$routeProvider', function($routeprovider){
$routeprovider.
when('/', {
template: 'Ok'
})
}]);
Related
I'm working with an Angular-Gulp-Browsersync-Express app and I'm having trouble getting angular's $http resource to POST a simple "contact us" form to my express server.
Every time I try to submit my form I get the following error:
POST http://localhost:8080/submitContactUsForm 404 (Not Found)
Cannot POST /submitContactUsForm
To be up front, I've got much more experience working with the front-end than I do with the back-end so it could very well be that I've got the wrong server setup.
Here is my Express Server:
'use strict';
var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var http = require('http');
var routes = require('.././src/index.module.js');
// var contactController = require('.././api/http/controllers/contactcontroller.js');
// require database data modeling via mongoose
var mongoose = require('mongoose');
// Express Session allows us to use Cookies to keep track of
// a user across multiple pages. We also need to be able to load
// those cookies using the cookie parser
var session = require('express-session');
var cookieParser = require('cookie-parser');
// Flash allows us to store quick one-time-use messages
// between views that are removed once they are used.
// Useful for error messages.
var flash = require('connect-flash');
// Use express and set it up
var app = express();
app.use(cors());
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.post('/submitContactUsForm', function(req, res) {
console.log('it hit the server');
})
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync').create();
var browserSyncSpa = require('browser-sync-spa');
var util = require('util');
var proxyMiddleware = require('http-proxy-middleware');
function browserSyncInit(baseDir, browser) {
browser = browser === undefined ? 'default' : browser;
var routes = null;
if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) {
routes = {
'/bower_components': 'bower_components'
};
}
browserSync.instance = browserSync.init({
startPath: '/',
cors: true,
browser: browser,
port: 8080,
server: {
baseDir: baseDir,
routes: routes,
middleware: function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
next();
}
},
});
}
browserSync.use(browserSyncSpa({
selector: '[ng-app]'// Only needed for angular apps
}));
gulp.task('serve', ['setenvconstants','watch'], function () {
browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]);
});
gulp.task('serve:dist', ['setenvconstants','build'], function () {
browserSyncInit(conf.paths.dist);
});
gulp.task('serve:e2e', ['inject'], function () {
browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []);
});
gulp.task('serve:e2e-dist', ['build'], function () {
browserSyncInit(conf.paths.dist, []);
});
Here is the Angular Controller I am trying to post from:
(function() {
'use strict';
angular
.module('commonSenseDietApp')
.controller('ContactController', ContactController);
function ContactController($http, $log) {
// controllerAs syntax
var vm = this;
vm.contactInfo = {
email: vm.email
}
vm.processContactForm = function() {
return $http.post('/submitContactUsForm', vm.contactInfo)
.then(returnSendSuccessful)
.catch(sendFail);
function returnSendSuccessful(response) {
$log.log(response.data);
return response.data;
}
function sendFail(err) {
return $log.error(err.data);
}
}
}
})();
Here are my Client-Side Routes:
(function() {
'use strict';
angular
.module('commonSenseDietApp')
.config(routeConfig);
function routeConfig($routeProvider) {
// Home Page
$routeProvider
.when('/', {
templateUrl: 'app/views/pages/home.html',
controller: 'MainController',
controllerAs: 'vm'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
// About Page
$routeProvider
.when('/about', {
templateUrl: 'app/views/static/about.html'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
// Terms of Use Page
$routeProvider
.when('/terms-of-use', {
templateUrl: 'app/views/static/terms-of-use.html'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
// Privacy Policy Page
$routeProvider
.when('/privacy-policy', {
templateUrl: 'app/views/static/privacy-policy.html'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
// Contact Us Page
$routeProvider
.when('/contact', {
templateUrl: 'app/views/pages/contact.html',
controller: 'ContactController',
controllerAs: 'vm'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
// Answer Page
$routeProvider
.when('/answer', {
templateUrl: 'app/views/pages/answer.html',
controller: 'AnswerController',
controllerAs: 'vm'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
// How It Works Page
$routeProvider
.when('/how-it-works', {
templateUrl: 'app/views/static/how-it-works.html'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
// Algorithm Explainer Page
$routeProvider
.when('/meet-ONNA', {
templateUrl: 'app/views/static/meet-ONNA.html'
})
.otherwise({
controller: 'Error404Controller',
templateUrl: 'app/views/errors/404.html'
});
}
})();
Here is my contact form markup:
<section>
<div class="contact-us-title">
<h1>Contact Us</h1>
</div>
<form class="contact-us-form" name="contactUsForm" ng-submit="vm.processContactForm()">
<div class="form-group">
<input placeholder="name" type="text" name="name" ng-model="vm.name" class="form-control" required />
<span class="label label-danger" ng-show="vm.submitted && contact-us-form.name.$error.required">Required!</span>
</div>
<div class="form-group">
<input placeholder="Email" type="email" name="email" ng-model="vm.email" class="form-control" required />
<span class="label label-danger" ng-show="vm.submitted && contact-us-form.email.$error.required">Required!</span>
<span class="label label-danger" ng-show="vm.submitted && contact-us-form.$error.email">Invalid email!</span>
</div>
<div class="form-group">
<input name="headline" placeholder="Headline" type="text" ng-model="vm.headline" class="form-control" required/>
<span class="label label-danger" ng-show="vm.submitted && contact-us-form.headline.$error.required">Required!</span>
</div>
<div class="form-group">
<textarea name="message" placeholder="Message" type="textbox" ng-model="vm.message" class="form-control" required></textarea>
<span class="label label-danger" ng-show="vm.submitted && contact-us-form.subjectList.$error.required">Required!</span>
</div>
<input type="submit" id="submit-contact-form-btn">
</form>
</section>
I'm also not seeing anything logging to console in the terminal. Any insight on this would be super helpful and very appreciated.
Eureka I found the answer!
Turns out my lack of experience with express playing nice with browersync was certainly a hinderance for me here. The answer lied in Proxying browsersync to express and the use of gulp-nodemon package. After some restructuring I've got the right setup:
My Browser-Sync server and gulp init tasks:
'use strict';
var path = require('path');
var port = process.env.PORT || 8080;
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync').create();
var browserSyncSpa = require('browser-sync-spa');
var util = require('util');
var proxyMiddleware = require('http-proxy-middleware');
var nodemon = require('gulp-nodemon');
var reload = browserSync.reload;
function browserSyncInit(baseDir, browser) {
var routes = null;
if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) {
routes = {
'/bower_components': 'bower_components'
};
}
browserSync.instance = browserSync.init({
startPath: '/',
cors: true,
browser: browser = browser === undefined ? 'default' : browser,
proxy: 'http://localhost:8081',
port: port
// https: true
});
}
browserSync.use(browserSyncSpa({
selector: '[ng-app]' // Only needed for angular apps
}));
// Run Gulp tasks
gulp.task('serve', ['browser-sync','setenvconstants','watch']);
gulp.task('browser-sync', ['nodemon'], function () {
browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]);
});
gulp.task('serve:dist', ['setenvconstants','build'], function () {
browserSyncInit(conf.paths.dist);
});
gulp.task('serve:e2e', ['inject'], function () {
browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []);
});
gulp.task('serve:e2e-dist', ['build'], function () {
browserSyncInit(conf.paths.dist, []);
});
gulp.task('nodemon', [], function(done) {
var running = false;
return nodemon({
script: 'api/app.js',
watch: ['api/**/*.*', 'src/**/*.*']
})
.on('start',function() {
if (!running) {
done();
}
running = true;
})
.on('restart', function() {
setTimeout(function(){
reload();
}, 500);
});
});
My Express server:
var express = require('express');
var bodyParser = require('body-parser');
var http = require('http');
var port = process.env.PORT || 8081;
var cors = require('cors');
var path = require('path');
var publicRoutes = require('./http/routes/web.js');
// require database data modeling via mongoose
var mongoose = require('mongoose');
// Express Session allows us to use Cookies to keep track of
// a user across multiple pages. We also need to be able to load
// those cookies using the cookie parser
var session = require('express-session');
var cookieParser = require('cookie-parser');
// Flash allows us to store quick one-time-use messages
// between views that are removed once they are used.
// Useful for error messages.
var flash = require('connect-flash');
// Use Express and set it up
var app = express();
app.use(bodyParser.urlencoded({extended: true}));
// Parse requests to JSON
app.use(bodyParser.json({type: '*/*', limit: '50mb'}));
// set Jade as the view engine
app.set('view engine', 'jade');
// tell server where to find our views
app.set('views', __dirname + '/.././src/app/views');
// make sure bower components are installed.
app.use('/underscore', express.static(path.resolve('.././node_modules/underscore')));
// tell our server where to find static assets depending on the environment.
process.env.NODE_ENV == 'production' ? app.use(express.static(path.join(__dirname + '/../..'))) : app.use(express.static(path.join(__dirname + '/.././dist')));
// enable cors
app.use(cors({
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"allowedHeaders": ["Origin, X-Requested-With, Content-Type, Accept, Authorization"],
"preflightContinue": false
}));
// Pull in our public routes
app.use('/api', publicRoutes);
// Listen
app.listen(port, function(error) {
if (error) {
console.error(error);
} else {
console.info("==> 🌎 Listening on port %s. Visit http://localhost:%s/ in your browser.", port, port);
}
});
I'm now able to $http.post from my Angular controller considering the route prefix in my express server:
vm.processContactForm = function() {
return $http.post('/api/submitContactUsForm', vm.contactInfo)
.then(returnSendSuccessful)
.catch(sendFail);
function returnSendSuccessful(response) {
$log.log(response);
// return response.data;
}
function sendFail(err) {
return $log.error(err.data);
}
}
The only issue I'm having now is with...
process.env.NODE_ENV == 'production' ? app.use(express.static(path.join(__dirname + '/.././src'))) : app.use(express.static(path.join(__dirname + '/.././dist')));
wherein '/dist' is served just fine but '/src' only serves a blank index.html page to my localhost. I'll post this as a new question and consider this issue solved. Thanks for the help!
I am building a MEAN-stack application and am finally getting to the point of creating a user authentication. To do so, I followed this tutorial: http://code.tutsplus.com/tutorials/authenticating-nodejs-applications-with-passport--cms-21619
Now, when I incorporate this into my project it works, but only partially. Namely, it seems that the only page I can navigate to properly is the app's home page. If I click on any links or type something other than home in the address bar, it takes me back to the login screen.
What are some possible reasons for that?
My routes/index.js file looks as follows:
var express = require('express');
var router = express.Router();
var isAuthenticated = function (req, res, next) {
// if user is authenticated in the session, call the next() to call the next request handler
// Passport adds this method to request object. A middleware is allowed to add properties to
// request and response objects
if (req.isAuthenticated())
return next();
// if the user is not authenticated then redirect him to the login page
res.redirect('/');
}
module.exports = function(passport){
/* GET login page. */
router.get('/', function(req, res) {
// Display the Login page with any flash message, if any
res.render('index', { message: req.flash('message') });
});
/* Handle Login POST */
router.post('/login', passport.authenticate('login', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash : true
}));
/* GET Registration Page */
router.get('/signup', function(req, res){
res.render('register',{message: req.flash('message')});
});
/* Handle Registration POST */
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/home',
failureRedirect: '/signup',
failureFlash : true
}));
/* GET Home Page */
router.get('/home', isAuthenticated, function(req, res){
res.render('home', { user: req.user });
});
/* Handle Logout */
router.get('/signout', function(req, res) {
req.logout();
res.redirect('/');
});
return router;
}
I also have some AngularJS routes specified in another file (application worked perfectly with these before I started adding authentication).
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
})
.when('/calendar',{
templateUrl: 'partials/calendar.html',
//controller: 'Calendar'
})
.when('/add-activity', {
templateUrl: 'partials/activity-form.html',
controller: 'AddActivityCtrl'
})
.when('/activity/:id',{
templateUrl: 'partials/activity-form.html',
controller: 'EditActivityCtrl'
})
.when('/activity/delete/:id', {
templateUrl: 'partials/activity-delete.html',
controller: 'DeleteActivityCtrl'
})
.otherwise({
redirectTo: '/'
});
}]);
Is there something I am missing?
P.S. I noticed that currently my URL of home page is
http://localhost:3000/home#/
whereas previously it was
http://localhost:3000/#/
I added "home" to differentiate from "/" which is the authentication page; however, I am unsure about how "#" is tacked onto the path in the first quote.
I was able to resolve this as follows. I changed the Express routing to contain a
"login"
route and changed the home route to just
"/"
As a result, the home path became
http://localhost:3000/#/
The hash sign is tacked on by and for the Angular. From my understanding, the Angular treats such path as "/". Then, the remaining routing is done by Angular and I have a single-page AngularJS app.
Working code:
Express
var express = require('express');
var router = express.Router();
module.exports = function(passport){
var isAuthenticated = function (req, res, next) {
// if user is authenticated in the session, call the next() to call the next request handler
// Passport adds this method to request object. A middleware is allowed to add properties to
// request and response objects
if (req.isAuthenticated()){
//console.log(next());
return next();
}
// if the user is not authenticated then redirect him to the login page
res.redirect('/login');
}
/* GET login page. */
router.get('/login', function(req, res) {
// Display the Login page with any flash message, if any
res.render('login', { message: req.flash('message') });
});
/* Handle Login POST */
router.post('/login', passport.authenticate('login', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash : true
}));
/* GET Registration Page */
router.get('/signup', function(req, res){
res.render('register',{message: req.flash('message')});
});
/* Handle Registration POST */
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/',
failureRedirect: '/signup',
failureFlash : true
}));
/* GET Home Page when logged in */
router.get('/', isAuthenticated, function(req, res){
res.render('index', { user: req.user });
});
/* GET Home Page */
router.get('/', isAuthenticated, function(req, res){
res.render('index', { user: req.user });
});
/* Handle Logout */
router.get('/signout', function(req, res) {
req.logout();
res.redirect('/login');
});
return router;
}
Working code: Angular
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
})
.when('/calendar',{
templateUrl: 'partials/calendar.html',
//controller: 'Calendar'
})
.when('/add-activity', {
templateUrl: 'partials/activity-form.html',
controller: 'AddActivityCtrl'
})
.when('/activity/:id',{
templateUrl: 'partials/activity-form.html',
controller: 'EditActivityCtrl'
})
.when('/activity/delete/:id', {
templateUrl: 'partials/activity-delete.html',
controller: 'DeleteActivityCtrl'
})
.otherwise({
redirectTo: '/'
});
}]);
I have the following config in angular
.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: '../pages/main.html',
controller: 'RMController',
controllerAs: 'rm'
})
.when('/:user', {
templateUrl: '../pages/emp-details.html'
})
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
This works fine if click on something in main.html, which then takes me to the emp-details.html.
But, if I explicitly type localhost:8080/1234 (emp-details.html with param), express has never heard of that route.
What is the best way to handle this kind of relationship?
My routes looks like this:
module.exports = function(app, schema) {
//Finds all users
app.get('/api/users', function(req, res){
schema.getEmployees()
.then(function(results) {
res.json(results);
}, function(err) {
console.log(err);
if (err) res.json(err);
});
});
app.get('/api/users/:user', function(req, res) {
schema.getSpecificEmployee(req.params.user)
.then(function(results) {
res.json(results);
}, function(err) {
console.log(err);
if (err) res.json(err);
});
});
//Our default path: index.html
app.get('*', function(req, res){
res.sendFile(path.join(__dirname + '/public/index.html'));
});
}
Try doing this:
.when('/:user', {
url: '/emp-detail', //add this line
templateUrl: '../pages/emp-details.html'
})
Now if you do localhost:8080/#/emp-detail, you should see the emp-details.html page.
By using localhost:8080/#/xyz u should be able to access your routes.
Hope this works!!!
My RESTful MEAN application has a node.js server for back end and HTTP-server in the front end. Following is the project structure:
When i run My Directory/app/HTTP-server from the console and do the browsing its displaying the page as follows with directory listing/browsing:
Once i click on views the pages are rendering. Following is my app.js:
'use strict';
var app = angular.module('app', ['ngRoute', 'authControllers', 'authServices']);
var authControllers = angular.module('authControllers', []);
var authServices = angular.module('authServices', []);
var options = {};
options.api = {};
//dev URL
options.api.base_url = "http://localhost:3000";
app.config(['$locationProvider', '$routeProvider',
function($location, $routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/home.html',
controller: 'authCtrl'
}).
when('/login', {
templateUrl: 'partials/signin.html',
controller: 'authCtrl'
}).
when('/register', {
templateUrl: 'partials/signup.html',
controller: 'authCtrl'
}).
when('/me', {
templateUrl: 'partials/me.html',
controller: 'authCtrl'
}).
otherwise({
redirectTo: '/'
});
}]);
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('TokenInterceptor');
}]);
app.run(function($rootScope, $location, $window, AuthenticationService) {
$rootScope.$on("$routeChangeStart", function(event, nextRoute, currentRoute) {
//redirect only if both isAuthenticated is false and no token is set
if (nextRoute != null && nextRoute.access != null && nextRoute.access.requiredAuthentication
&& !AuthenticationService.isAuthenticated && !$window.sessionStorage.token) {
$location.path("/login");
}
});
});
server.js:
var express = require('express'),
jwt = require('express-jwt'),
bodyParser = require('body-parser'),
morgan = require('morgan'),
methodOverride = require('method-override'),
errorHandler = require('express-error-handler'),
tokenManager = require('./server/config/token_manager'),
secret = require('./server/config/secret'),
http = require('http'),
path = require('path');
var app = module.exports = express();
app.set('port', process.env.PORT || 3000);
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(express.static(path.join(__dirname, 'app')));
var routes = require('./server/routes');
routes.users = require('./server/routes/users.js');
var env = process.env.NODE_ENV || 'development';
// development only
if (env === 'development') {
app.use(errorHandler());
}
// production only
if (env === 'production') {
// TODO
}
app.all('*', function(req, res, next) {
res.set('Access-Control-Allow-Origin', 'http://localhost');
res.set('Access-Control-Allow-Credentials', true);
res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT');
res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization');
if ('OPTIONS' == req.method) return res.send(200);
next();
});
/*
Login
*/
app.post('/login', routes.users.login);
app.post('/user/register', routes.users.register);
app.get('/me', routes.users.me);
/*
Logout
*/
app.get('/logout', jwt({secret: secret.secretToken}), routes.users.logout);
process.on('uncaughtException', function(err) {
console.log(err);
});
/**
* Start Server
*/
http.createServer(app).listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'));
});
What needs to be done to disable this directory listing/browsing or to simply render my view on http://localhost:8080/ ?
In your server.js change
express.static(path.join(__dirname, 'app'));
with
express.static(path.join(__dirname, 'app'), {index: false});
I have my routes.js
module.exports = function(app) {
//I can't use this because angular routing does not work
/*app.get('*', function(req, res) {
res.sendfile('./public/index.html');
});*/
app.get('/submit', function(req,res){
res.sendfile('./public/submit.html');
});
app.get('/schedule', function(req,res){
res.sendfile('./public/schedule.html');
});
app.get('/requests', function(req,res){
res.sendfile('./public/requests.html');
});
app.get('/tv_left', function(req,res){
res.sendfile('./public/tv_left.html');
});
app.get('/tv_center', function(req,res){
res.sendfile('./public/tv_center.html');
});
app.get('/tv_right', function(req,res){
res.sendfile('./public/tv_right.html');
});
app.get('/', function(req, res){
res.sendfile('./public/index.html');
});
};
and my appRoutes.js like this
angular.module('appRoutes', []).config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
// home page
.when('/', {
templateUrl: 'index.html',
controller: 'LoginController'
})
.when('/submit', {
templateUrl: 'submit.html',
controller: 'SubmitController'
});
$locationProvider.html5Mode(true);
}]);
basicly if I use app.get('*'), then any request will go back to index.html, eventhough the url changed.
That's because express handles routes in the order they are defined. If you want index.html as a catch-all route, move it to the bottom of the function.
Further reading: https://www.safaribooksonline.com/blog/2014/03/10/express-js-middleware-demystified/