MEAN Stack routing issue, angular routing does not work - javascript

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/

Related

Reconciling Express (Passport) and AngularJS Routes

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: '/'
});
}]);

Handle routes when using Angular combined with Express (Node.js)

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!!!

Client Side Routhing with Angular on Node.js & Express

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'
})
}]);

Refresh specific page with Angular, Express and Jade (using html5mode)

I'm trying to refresh a page and execute client route to open a template inside ng-view
Index.jade
extends layouts/default
block content
section(data-ng-view)
script(type="text/javascript").
window.user = !{user};
default.jade
doctype html
html(lang='en', xmlns='http://www.w3.org/1999/xhtml', xmlns:fb='https://www.facebook.com/2008/fbml', itemscope='itemscope', itemtype='http://schema.org/Product')
include ../includes/head
body
div(data-ng-include="'static/modules/core/views/core.header.view.html'", data-role="navigation")
div(data-ng-include="'static/modules/core/views/core.index.view.html'", data-role="navigation")
div(data-ng-include="'static/modules/core/views/core.menu.view.html'", data-role="navigation")
div(data-ng-include="'static/modules/core/views/core.footer.view.html'", data-role="navigation")
include ../includes/foot
Server route
// Camera Routes
app.get('/api/cameras', cameras.all);
app.post('/api/cameras', auth.requiresLogin, cameras.create);
app.get('/api/cameras/:cameraId', cameras.show);
app.put('/api/cameras/:cameraId', auth.requiresLogin, auth.article.hasAuthorization, cameras.update);
app.del('/api/cameras/:cameraId', auth.requiresLogin, auth.article.hasAuthorization, cameras.destroy);
app.param('cameraId', cameras.camera);
// Home route
app.get('/', index.render);
express.js
/**
* Module dependencies.
*/
var express = require('express');
var flash = require('connect-flash');
var helpers = require('view-helpers');
var config = require('./config');
module.exports = function(app, passport) {
console.log('Initializing Express');
app.set('showStackError', true);
//Prettify HTML
app.locals.pretty = true;
//Should be placed before express.static
app.use(express.compress({
filter: function(req, res) {
return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
},
level: 9
}));
//Setting the fav icon and static folder
app.use(express.favicon());
app.use('/static',express.static(config.root + '/public'));
//Don't use logger for test env
if (process.env.NODE_ENV !== 'test') {
app.use(express.logger('dev'));
}
//Set views path, template engine and default layout
app.set('views', config.root + '/app/views');
app.set('view engine', 'jade');
//Enable jsonp
app.enable("jsonp callback");
app.configure(function() {
//cookieParser should be above session
app.use(express.cookieParser());
// request body parsing middleware should be above methodOverride
app.use(express.urlencoded());
app.use(express.json());
app.use(express.methodOverride());
//express/mongo session storage
app.use(express.session({ secret: '$uper$ecret$e$$ionKey'}));
//connect flash for flash messages
app.use(flash());
//dynamic helpers
app.use(helpers(config.app.name));
//use passport session
app.use(passport.initialize());
app.use(passport.session());
//routes should be at the last
app.use(app.router);
//Assume "not found" in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
app.all('/*', function(req, res, next) {
res.render('index.jade', {'root': 'app/views/'});
});
app.use(function(err, req, res, next) {
//Treat as 404
if (~err.message.indexOf('not found')) return next();
//Log it
console.error(err.stack);
//Error page
res.status(500).render('500', {
error: err.stack
});
});
//Assume 404 since no middleware responded
app.use(function(req, res, next) {
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not found'
});
});
});
};
HTML5 ENABLE
//Setting HTML5 Location Mode
angular.module('mean').config(['$locationProvider',
function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix("!");
}
]);
Client router here, I want to show this template inside ng-view
angular.module('mean').config(['$stateProvider',
function ($stateProvider) {
$stateProvider.
state('viewCamera', {
url: "/cameras/:cameraId",
templateUrl: 'static/modules/cameras/views/cameras.camera.view.html'
});
}
]);
Index view with ui-view tag
<section data-ng-controller="MapController" data-ng-init="find()">
<div ui-view>
</div>
<div class="map-content" ng-class="{'map-content-left': cameraOpen != undefined}">
<leaflet defaults="defaults" center="center" class="map"></leaflet>
</div>
</section>
My html head
head
base(href='/')
What I want? When insert this url manually: localhost:3000/cameras/12, call server and get index to call client route and open the template inside ng-view
What's the problem? When I insert this url in browser, I get the index.jade with download mode
What I already tried?
Change the server route to this (apparently this return rendered index)
// Home route
app.get('*', index.render);
But the client route is never called
What's wrong?
EDIT 1
My dependencies version
"angular": "latest",
"angular-resource": "latest",
"angular-cookies": "latest",
"angular-mocks": "latest",
"angular-ui-utils": "0.0.4",
"angular-translate": "~2.5.2",
"angular-translate-loader-static-files": "~2.5.2",
"ngDialog": "~0.3.7",
"angular-leaflet-directive": "~0.7.10",
"leaflet.markercluster": "~0.4.0",
"angular-loading-bar": "~0.6.0",
"angular-ui-router": "~0.2.13"
I'm using Mean-Stack-Relacional from here: https://github.com/jpotts18/mean-stack-relational
EDIT 2
I was using angular-route, so I changed to ui-router to see if the problem was solved.
EDIT 3
Client Route core
//Setting up route
angular.module('mean').config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider.
state('login', {
url: '/login',
template: '',
controller: 'SessionController',
data: {
method: "login"
}
})
.state('signin', {
url: '/signin',
template: '',
controller: 'SessionController',
data: {
method: "signin"
}
})
.state('home', {
url: '/',
resolve: {
resetMap: function ($q, $location, $rootScope) {
$rootScope.$emit('rootScope:emit', '');
}
}
});
}
]);
#Scymex help me to find this issue:
For anybody who might be using Jade, here's a quick gotcha: div(ui-view) compiles to <div ui-view="ui-view"></div>. What you need is div(ui-view="").
So, you can have ui-view inside ng-include, but need do this trick
Font: https://github.com/angular-ui/ui-router/issues/679
You're using HTML5 routes with a hashbang fallback. What that means is you want to set your server up so that requests to /cameras/12 redirect to /#!/cameras/12. The server will then render your Angular application, which will detect that it wants to go to your viewCamera state and will rewrite the url on the client.
You can accomplish this by simply adding the following middleware to your express app:
app.use(function (req, res, next) {
res.set('Location', '/#!' + req.path)
.status(301)
.send();
});

Angular - 404 when directly visiting localhost:8080/somePage, but OK on href link?

Only after adding CRUD to my angular controller and service do I get a 404 error when I visit localhost:8080/somePage directly..
Cannot GET /somePage
The href links in my navbar that point to the same URL are still working though!
<li>somePage</li>
Some admin pages won't have page links though, so I need to get to them directly. Any suggestions?
Going to look at the API directly via localhost:8080/api/stuff does display the json:
[ {
"text": "item 1",
"done": false,
"id": "53402c4390dfad962a000001",
"_v": 0 } ]
Here's my appRoutes.js
angular.module('appRoutes', []).config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
// home page
.when('/', {
templateUrl: 'views/home.html',
controller: 'mainController'
})
//
.when('/somePage', {
templateUrl: 'views/somePage.html',
controller: 'mainController'
});
$locationProvider.html5Mode(true);
}]);
Here's the node+express server.js:
// set up ======================================================================
var express = require('express');
var app = express(); // create our app w/ express
var mongoose = require('mongoose'); // mongoose for mongodb
var port = process.env.PORT || 8080; // set the port
var database = require('./config/database'); // load the database config
// configuration ===============================================================
mongoose.connect(database.url); // connect to mongoDB database on modulus.io
app.configure(function() {
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(express.logger('dev')); // log every request to the console
app.use(express.bodyParser()); // pull information from html in POST
app.use(express.methodOverride()); // simulate DELETE and PUT
});
// routes ======================================================================
require('./app/routes.js')(app); // load the routes
// listen (start app with node server.js) ======================================
app.listen(port);
console.log("App listening on port " + port);
And here's the Node.js routes.js, per Iqbal Fauzi's comment..
// load the stuff model
var Stuff = require('./models/stuff');
// expose the routes to our app with module.exports
module.exports = function(app) {
// api ---------------------------------------------------------------------
// get all the stuff
app.get('/api/stuff', function(req, res) {
// use mongoose to get all the stuff in the database
Stuff.find(function(err, stuff) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)
res.json(stuff); // return all the stuff in JSON format
});
});
// create stuff and send back all the stuff after creation
app.post('/api/stuff', function(req, res) {
// create stuff, information comes from AJAX request from Angular
Stuff.create({
text : req.body.text,
done : false
}, function(err, stuff) {
if (err)
res.send(err);
// get and return all the stuff after you create another
Stuff.find(function(err, stuff) {
if (err)
res.send(err)
res.json(stuff);
});
});
});
// delete stuff
app.delete('/api/stuff/:stuff_id', function(req, res) {
Stuff.remove({
_id : req.params.stuff_id
}, function(err, stuff) {
if (err)
res.send(err);
// get and return all the stuff after you create another
Stuff.find(function(err, stuff) {
if (err)
res.send(err)
res.json(stuff);
});
});
});
// application -------------------------------------------------------------
app.get('/', function (req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
// commented out for testing this problem.. because this otherwise redirects..
// app.get('*', function (req, res) {
// res.redirect('/'); // redirect to / and index.html will be served
// });
};
Uncomment your app.get('*', function (req, res) and instead of redirecting it to '/' you will better return the index.html file, let AngularJS handle the browser URL for you.
app.get('*', function (req, res) {
res.sendfile('./public/index.html');
});

Categories

Resources