SPA Design & Routing: AngularJS, TaffyDB, & ExpressJS - angularjs

I have been using AngularJS for a few months now. I have been using a Java backend for all of my AngularJS applications. Now I'd like to learn how to program full-stack JavaScript applications. I've never programmed in NodeJS.
The current design of my app has Angular taking care of all the routing, which is what I am most comfortable with. However, I am not sure if that is good design when using NodeJS and Express on the backend. In the past, my backend has been responsible for exposing a REST API that my frontend could leverage, and manipulating JSON data. I didn't use it for anything else.
This is how Angular is managing the routing in my full-stack JS app
(function()
{
angular
.module('passGen', [
'ui.router',
'ngAnimate',
'passGen.generator',
'passGen.registration',
'passGen.tabs',
'passGen.main'
])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider)
{
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'partials/main.html'
})
.state('registration', {
url: '/register',
templateUrl: 'partials/registration.html'
})
.state('products', {
url: '/products',
});
}]);
})();
I want to add user registration functionality to the application. This is where TaffyDB and Node come into play. I'd like the backend to maintain and serve all of the user registration data in order to avoid overloading the frontend.
Right now all I'm trying to do is post some data in NodeJS to the /products route, but it's not doing anything. This is reflected in the comments.
server.js
(function()
{
// modules
var express = require('express');
var path = require('path');
var TAFFY = require('taffy');
var app = express();
app.use(express.static('src/app'));
var products = TAFFY([{
'item':1,
'name':'Shark'
}]);
// I don't think this is necessary
app.get('/#/home', function(req, res)
{
res.sendFile(path.join('/index.html'));
});
// Not doing anything, also doesn't work with the '/products' path
app.post('/#/products', function(req, res)
{
res.send(products);
console.log(products);
});
app.listen(8878);
})();
Perhaps I need to take a deeper look at ExpressJS routing documentation, or refine my Google queries.
I have some questions:
Should I use AngularJS or ExpressJS to handle the routing?
If I can use AngularJS for the routing, then should I be able to use ExpressJS to handle HTTP requests?
Why isn't app.post working in server.js?

Related

Routing working locally, not on Heroku servers

My AngularJS application won't route to /login when accessing /login directly. It will route to /login if I first access / then route from / to /login.
It is working on my local environment but not with Heroku servers. Are there some settings I have to configure on the Heroku server?
I am using angular-ui-router to route to different states throughout my application.
My app.js config snippet looks like this:
angular.module('app', [
angularUiRouter
])
.config(($stateProvider) => {
"ngInject";
$stateProvider
.state("home", {
url: "/",
template: "<home></home>"
})
.state("login", {
url: "/login",
template: "<login></login>"
});
})
Answering my own question.
Since the setup on this application is using MEAN stack, we have to also add routing from server side to client.
For all templates in AngularJS there has to be a routing from Express to AngularJS to index.html
for all templates and routings created in angular we need to get the request and send index.html in response
when we use angularjs stateProvider to route in Angularjs.., we have to also add routing to /dist/index.html from server side.
$locationProvider.html5Mode(true).hashPrefix('!'); has to be defined in app.js on AngularJS side
A snippet of my Server.js file:
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/dist'));
app.get('/', function(req, res){
res.sendFile(__dirname + '/dist/index.html');
});
app.get('/login', function(req, res){
res.sendFile(__dirname + '/dist/index.html');
});

Angular URL routing issue

So I needed to change my URL so that google analytics could track it. Google analytics wouldn't accept it with the "/#/" (hash) in the link. That said, I used Angular's locationProvider and revised my app routing with:
(function() {
'use strict';
angular
.module('mbapp')
.config(routerConfig);
/** #ngInject */
function routerConfig($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainController',
controllerAs: 'main'
});
$stateProvider
.state('steps', {
url: '/steps',
templateUrl: 'app/steps/steps.html',
controller: 'StepsController',
controllerAs: 'steps'
});
// use the HTML5 History API
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise('/');
}
})();
My URL is fine and changes it to http://website.com/steps rather than http://website.com/#/steps. However, now, if a user refreshes (f5) the link it then throw a 404 error and not sure why. Additionally, it seems that somehow this gets injected as the URL when the refresh is called "http://website/steps#/steps".
Any ideas on this?
Thanks much.
The problem is probably on the server side. You have to configure your server so it responds to every request with your html file. For example in express:
var app = require('express')();
app.configure(function(){
// static - all our js, css, images, etc go into the assets path
app.use('/assets', express.static('/assets'));
app.get('/api/users/:id', function(req, res){
// return data for user....
});
// This route deals enables HTML5Mode by forwarding missing files to the index.html
app.all('/*', function(req, res) {
res.sendfile('index.html');
});
});
When you reload the page, the request goes to the server side of your application, and it tries to resolve the url but it probably can't, because those routes only exists on the client side of your application.
Also it is a good idea to prefix every server side route with an /api route prefix, so you can easily distinguish between client side and server side routes.

How to force login in angular full stack yeoman?

Is there a way to force the user to log in first in an app generated by the angular full stack yeoman ?
I tried to add the following code in the run part of app.js but was not successful
Auth.isLoggedIn(function(loggedIn) {
console.log(loggedIn);
if (!loggedIn) {
console.log("redirecting");
// event.preventDefault();
$state.go('login');
}
});
I found authentication controls in api index.js files but none for the / landing page ...
Thx
I did not use google as i should have !
To force authentication for a state, just add
authenticate: true
in the state (or all states in my case)
Without more code or information on which router you are using (generator-angular-fullstack supports both the default NgRouter and UIRouter) it is tough to give a complete answer. By your answer to your question I am assuming you have UI Router and have figured out how to do client side authentication within the generated fullstack code. However, you will also need to implement something similar to what they have done in their 'users' api to protect your api end points on the server side and return a 401/403 error.
'use strict';
var express = require('express');
var controller = require('./user.controller');
var config = require('../../config/environment');
var auth = require('../../auth/auth.service');
var router = express.Router();
router.get('/', auth.hasRole('admin'), controller.index);
router.delete('/:id', auth.hasRole('admin'), controller.destroy);
router.get('/me', auth.isAuthenticated(), controller.me);
router.put('/:id/password', auth.isAuthenticated(), controller.changePassword);
router.get('/:id', auth.isAuthenticated(), controller.show);
router.post('/', controller.create);
module.exports = router;
In the above code (which can be found by navigating to the server folder, then the api folder, then the user folder and looking at index.js) you will see that they are calling a couple of functions.
They are calling auth.hasRole('admin') and auth.isAuthenticated().
Those are functions which can be found in the server side auth/role service under the folder auth and in the auth.service.js file.
function hasRole(roleRequired) {
if (!roleRequired) throw new Error('Required role needs to be set');
return compose()
.use(isAuthenticated())
.use(function meetsRequirements(req, res, next) {
if (config.userRoles.indexOf(req.user.role) >= config.userRoles.indexOf(roleRequired)) {
next();
}
else {
res.status(403).send('Forbidden');
}
});
}
I think it is important to understand how this is working on the server side also. So, if you navigate to localhost:9000/admin and open console you will see that there is a 401 or 403 error depending on whether or not you are logged in and/or logged in as an admin user.
Just Paste authenticate:true on main.js
angular.module('testcesarApp')
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'app/main/main.html',
controller: 'MainCtrl',
authenticate:true
});
});

Can't navigate directly to URL Angular UI Router

This is my router file:
it's nested inside a require.js block and configured to work with Jade templates
define([
'./app',
'angular.uirouter'
], function(app, angularUIRouter) {
"use strict";
// ROUTES
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
// loads url from the index
$urlRouterProvider.otherwise('/');
$locationProvider.html5Mode(true);
$stateProvider
.state('dashboard', {
url:'/dashboard',
views: {
'core' : {
templateUrl: '/articles/dashboard'
}
}
})
}]);
});
And this is my Express.js router file:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('main', {
title: 'Express'
});
});
router.get('/dashboard', function(req, res) {
console.log("/dashboard requested");
});
router.get('/articles/:name', function (req, res) {
var name = req.params.name;
res.render('articles/' + name);
});
module.exports = router;
When I go to localhost:3000/dashboard, it's making a GET request to the server. How do I configure Angular UI Router to handle GET requests instead of the server?
Note: I can still go to localhost:3000/articles/dashboard and see the dashboard. Also,
a(ui-sref="dashboard")
loads the dashboard correctly.
Neither angular nor ui router can not handle server GET. Angular $locationProvider html5Mode solves only client-side setting - url does not contain # and location controls also path part in URL.
Html5 mode requires server side configuration. Every requests must return application entry point - usually index.html.
For example
router.get('/dashboard', function(req, res) {
res.sendfile('path-to/index.html');
});

AngularJs routing, multiple requests in server

I want to use angularjs routing, I'm using but it's making extra requests in server side. Anyone know the solution of this problem, or I'm doing something wrong?
Client app.js
app.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$locationProvider.html5Mode({enabled: true, requireBase: false})
$routeProvider.
when('/', {
templateUrl: '/tpl/main.tmp.html',
controller: 'MainCtrl'
})
.otherwise({redirectTo: '/'})
}])
//routes.js
app.get('/', function(req, res) {
console.log("test")
res.render(__dirname+'/public/tpl/index.html', siteConfig)
})
//output
//test
//test
//test
//test
Files:
models
public
|-css
|-js
|--app.js
|--angular.js
app.js
A few things may cause this, a closer inspection of both request packets might narrow down the cause. Some ideas to check for:
The browser keeps trying to fetch the site favicon because it can't find one
Fetching an image with a # in the URL (i.e. <img src="#"/>)
Meta refresh tag in the HTML
Web browsers may retry requests when the connection is closed before receiving a response

Resources