I'm following a tutorial on how to set up authentication with nodejs and passport. (http://scotch.io/tutorials/javascript/easy-node-authentication-setup-and-local)
The tutorial has me rendering templates with ejs and passing in flash data.
Instead of this, I'd like to use angularjs. The part I'm having trouble with is getting the flash data. I know how to use templates and send variables, but what in angular replaces the "req.flash('signupMessage')" in the below code?
This is the code the tutorial shows:
app.get('/signup', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('signup.ejs', { message: req.flash('signupMessage') });
});
This is the code where I set up my route
// public/js/appRoutes.js
angular.module('appRoutes', []).config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
// show signup form
.when('/signup', {
templateUrl: 'views/signup.html',
controller: 'SignupController'
});
$locationProvider.html5Mode(true);
}]);
Here is the controller:
// public/js/controllers/SetupCtrl.js
angular.module('SignupCtrl', []).controller('SignupController', function($scope) {
$scope.tagline = 'TEST';
});
A similar question was answered here: What is the proper way to log in users using Angular & Express?
TLDR: the answer posted was to the following link, where the author describes that you need to keep all the passport stuff on the server side, and then allow the client side (angular stuff) to request information about the session.
http://vickev.com/#!/article/authentication-in-single-page-applications-node-js-passportjs-angularjs
Related
I'm currently experimenting a little bit with my first app with angular-js, nodejs and a mongodb backend. This app and its URLs are managed by ngRoute from angular. In this app there is a little admin area with authentication (based on nodejs' client-sessions). This works so far pretty well. The authentication works with URLs managed by nodejs, but not with the ones of the routeProvider. The provider looks like this:
app.config(['$locationProvider', '$routeProvider', function ($locationProvider, $routeProvider) {
$routeProvider.when("/main",
{
templateUrl: "app/main/landing.html",
controller: "MainController"
})
.when("/admin",
{
templateUrl: "restricted",
controller: "AdminController"
})
.when("/login",
{
templateUrl: "app/login/login.html"
})
.otherwise({redirectTo: '/main'});
}]);
The restricted area (/admin) calls a get to the server and sends the view.html if user is valid:
app.get('/restricted', function (req, res) {
if (!req.session_state.user) {
res.res.status(302).redirect("/login");//Does not really work, should redirect to login, but endless loop
} else {
res.sendFile(path.resolve(__dirname + "/../views/restricted/admin.html"));
}
});
The server's restricted folder is outside of the static area provided by nodejs.
The problem is that deep links (when calling directly '#!/admin') there is an endless loop. How can this be solved? I already tried with differnt URLs and status codes. Is this a correct approach to realize authentication with routeProvider or is there a better one?
Simple question.
I'm building an Express web application with two views/routes (controlled by Angular):
localhost:3000/#/join
localhost:3000/#/find
I want the initial "localhost:3000" to forward to "localhost:3000/#/join", but currently, the page only loads the generic static content and does not include the unique html partial content associated with the view.
I'm using the following code.
require('./app/routes.js')(app);
app.all('*', function(req, res){
res.redirect('/#/join');
});
The forwarding works correctly for all url (e.g. localhost:3000/blah, localhost:3000/blah2, etc.) -- except for the initial localhost:3000.
Any suggestions?
Figured out the answer. I just need to include an "otherwise" statement at the end of my Angular routeProvider.
var app = angular.module('meanMapApp', ['addCtrl', 'queryCtrl','ngRoute'])
.config(function($routeProvider){
$routeProvider.when('/join', {
controller: 'addCtrl',
templateUrl: 'partials/addForm.html',
}).when('/find', {
controller: 'queryCtrl',
templateUrl: 'partials/queryForm.html',
}).otherwise({redirectTo:'/join'})
});
So I've been trying to find a solution for my problem during the last 7 days or so. I have almost given up on this so this is my last attempt at solving this.
I'm trying to build a recipe site which fetches the recipes from my Laravel API Backend (i.e. api/recipes returns all recipes in the MySQL-database). The data is requested from the AngularJS frontend via the $http-service, so far so good.
Single page applications like this isn't a problem since I've defined the routes in Laravel like this. All HTTP reqs who isn't sent to the RESTful API is redirect to my index-view where I want AngularJS to take over the routing from there on.
Route::get('/', function()
{
return View::make('index');
});
Route::group(array('prefix' => 'api'), function() {
Route::resource('recipes', 'RecipeController',
array('except' => array('create', 'edit', 'update')));
Route::resource('ingredients', 'IngredientController',
array('except' => array('create', 'edit', 'update')));
Route::resource('nutrients', 'NutrientController',
array('except' => array('create', 'edit', 'update')));
Route::resource('IngredientsByRecipe', 'IngredientsByRecipeController');
});
App::missing(function($exception)
{
return View::make('index');
});
I want the user to be able to edit existing recipes, create new ones etc. Therefore I've created these routes in Angular:
var recipeApp = angular.module('recipeApp', [
'ngRoute',
]);
recipeApp.config(['$routeProvider',
function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'list.html',
controller: 'MainCtrl'
})
.when('/edit/:recipeId', {
templateUrl: 'detail.html',
controller: 'EditCtrl'
})
.when('/new', {
templateUrl: 'detail.html',
controller: 'CreateCtrl'
})
.otherwise({
redirectTo: '/'
});
}
]);
Unfortunately I can't seem to get this to work even with this routing in Angular. I've seen similar problems being solved by decoupling the app and stuff like that, and I've tried something like that by running my Angular frontend at port 8888 and the Laravel backend at port 8000 but then I got a problem with CORS.
I'm eager to get this to work but can't seem to figure out how to get it to work. It seems like the browser ignores the Angular routing and only uses the Laravel routing, which means that I can only access the index view or the API. How should I solve this?
Building hybrid apps like this is something I would not recommend. You should separate your Laravel API backend from your AngularJS frontend. You can then set up services in AngularJS to call your API. API driven development is the way to go.
If you have problems with CORS, you can modify the headers in your Laravel responses to fix this. To fix the problem with every Laravel route, you can add the following somewhere at the top of your routes.php file:
header('Access-Control-Allow-Origin: *');
Or (better solution if you want it for all routes), add this to your after filter in filters.php:
$response->headers->set('Access-Control-Allow-Origin', '*');
Or you can set up a separate filter:
Route::filter('allowOrigin', function($route, $request, $response) {
$response->header('Access-Control-Allow-Origin', '*');
});
Now, to answer your question ...
In the head of your index file (for Angular), add <base href="/">, and also add $locationProvider.html5Mode(true); inside your Angular config; you can just place it after your $routeProvider.when('/', { ... }); function.
This might seem like a silly question.. but how do I pass req.user.username (for example) to all pages / globally after the user signs in with passport. This question can apply to any data I would like accessible for all pages...
On the server side, I have the below which sends allows routeProvider to handle all client side routing.
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)
})
I'm not sure if the solution is specific to passport... express or involves both...
The client side routing is handled by something like:
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {templateUrl: 'views/home.html'})
.when('/login', {templateUrl: 'views/login.html'})
.when('/users', {templateUrl: 'views/users.html', controller: 'UserController'})
...
You have two options. Either
BAD - include that data in your compiled view that is initially served (./public/index.html) or
GOOD/COMMON - fetch the data you need inside something like an Angular controller which is in your view; eg.
$routeProvider.when('/', {
templateUrl: 'views/home.html',
controller: function($scope, myThings) {
//myThings is a service that async fetches some data from api
myThings().then(function(user) {
$scope.user = user;
});
}
});
This obviously means you are exposing data on an api endpoint, but how else would angular be fetching the bits it needs since you said this is a single-page app?
Services are the way to go if you want to share global data among controllers, directives and other services.
Depending upon the type of data, you can expose services that load data from the server or services which do not need to make remote call to load data (like some custom view settings).
For example if in case you want to get the current logged in user.
The first thing is to create a method on the server that return the current logged in user data in json format.
Then create something like a UserService or SessionService that call this server method to load currently loggedin user data.
Something like
angular.module('myApp').factory('SessionService',['$http',function($http) {
var service={};
service.getCurrentUser=function() {
return $http('/user');
};
return service;
}]);
Inject this service into your controllers to get the current user. You can optimize it to cache the user data.
If you want to use the data in routeProvider use the resolve property
.when('/users', {templateUrl: 'views/users.html', controller: 'UserController',
resolve: {
currentUser:function(SessionService) {
return SessionService.getCurrentUser();
}
}}})
Express.js routing of /question/ask
app.get('/question/ask', function (req, res){
console.log('index.js');
console.log('came to question/:id');
res.render('app');
});
The corresponding angularjs routing is:-
when('/ask', {
templateUrl: 'partials/askQuestion',
controller: 'xController'
}).
whereas it should be:-
when('/question/ask', {
templateUrl: 'partials/askQuestion',
controller: 'xController'
}).
I'm working in $locationProvider.html5Mode(true); mode.
Is there anyway i can get the later angularjs routing working. I'm using angularjs 1.1.5 version.
Edit:-
app.get('/*', function (req, res){
console.log('index.js');
console.log('came to question/:id');
res.render('app');
});
has the same problem, the angular route only routes the last /ask for /question/ask.
The issue for me is that I can only do 1 of the following :-
www.example.com/question/:qId
www.example.com/discussion/:aId
because the application will catch only 1 when('/:id', { as it does not include the previous /question/ or /discussion/
Well, if you have the same routes on Express and Angular, if the user types the url directly in the browser you will hit the Express route, but if the user is navigating within the application, then he will hit the Angular route.
Is this what you want ?
What some do is to have a different set of routes on the server for the REST API, and a catch all route to serve the application no matter what the user type as a URL, bringing the user to the home page when a server route is hit. Within the application of course navigation is handled by Angular routes. The problem is that you get no deep linking.
Some other apps have the same routes on both the server and the client, this way they can serve some contents no matter what.
Some will write involved route rewriting to make sure that you both get the application bootstrapping code AND the required URL, thus allowing deep linking.
Cheers
using angular version 1.2.0-rc.3 cures the problem.
change:
var myApp = angular.module('myApp', []);
to
var myApp = angular.module('myApp', ['ngRoute']);
And include:-
script(type='text/javascript', src='js/angular-route.js')