How to pass request parameters back to Angular - javascript

I currently have an app which uses Express with Jade templates.
I'm building a new version of the app using Angular with client-side HTML.
I need access to certain request parameters in order to determine user permissions in my Angular code. My problem is that I don't know how to get ahold of these parameters in my Angular controllers/services.
Below is what currently occurs in Express with the Jade structure:
routes.js:
router.get('/player/:id',
playerRoute.show
);
player.js:
var show = function(req, res) {
res.render('player', {user: req.user});
};
...and now my new version's handler:
var player = function(req, res) {
//res.sendFile(path.join(__dirname, '../v2', 'index.html'));
res.json({user: req.user});
};
The correct user JSON is sent back to my client-side with the code above. When res.json is commented out and res.sendFile uncommented the correct HTML is rendered. My dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?

After all that, your question just boils down to:
MY dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
You don't. The usual case is to just render the HTML along with the assets needed to render the initial app (hide everything, show a splash screen whatever). Further data (like getting your user) is handled by API calls to your server via Angular's HTTP facilities. That means they are separate. After that API call, your app determines what to render.
Otherwise, you could just render the data in the HTML as some global variable and have Angular pick it up from there. This is messy IMO, but doesn't require a separate API call to get the data.

copied from my own answer to a similar question
To get a variable from server to client javascript try templating a json string into the html and loading it from the javascript. EJS handles quote escaping and I think Jade does too. For reference content!= safeString tells Jade to skip escaping, so does content !{safeString}.
- var user={id:1, displayName:'foo'}
#example
meta(data-userJSON=JSON.stringify(user))
script(src="//code.jquery.com/jquery-1.11.3.min.js")
script.
var user = JSON.parse(
$('#example meta').attr('data-userJSON')
)
console.log(user);
span #{user.id}
span #{user.displayName}

Here's how I ended up handling this situation. I simply created a new API endpoint which I can easily hit with an Angular service. Here's the Node setup:
routes.js:
router.get('/currentUser',
apiController.currentUser.index
);
currentUser.js:
var index = function(req, res) {
res.json({user: req.user});
};
module.exports = {
index: index
};
Still seems odd to me to make an API call to get the request parameters, but it works. Feedback appreciated.

Related

How should I display data from backend in Node.js + jade + angularJS + mongoose

I'm going to make web application (SPA) with:
Backend: Node.js (express)
Frontend: Jade + AngularJS
Database: Mongoose
I will send data (as a form) to backend in this way ExpressJS AngularJS POST (Check ANSWER)
It will be simple CRUD.
However i wondering how should I display data from backend?
For example:
I'll run application
var Partner = require('../model/partners');
router.get('/', function (req, res) {
Partner.find({}, function (err, partnerList) {
if (err) throw err;
res.render('campaign', {
partnerList: partnerList
});
});
});
And how should i display data (partnerList). Maybe in this way?
- each item in partnerList
= item.name
Or maybe there is another better way with angular to display data at view? I'm asking because later i'd like remove or update items from partnerList (CRUD operation). And it may be a problem because i will have to send item._id as a parameter to angular function?
For example if i will add button to remove record:
- each item in partnerList
= item.name
button(type='remove' ng-click="sub('#{item._id}')")
script.
app.controller('view1Ctrl', function($scope, $http) {
$scope.sub = function(id) {
$http.post('/',id).
success(function(data) {
console.log("posted successfully");
}).error(function(data) {
console.error("error in posting");
})
}
});
Probably it won't work correct
As said in previous coment, from my point of view I prefere to send the minimum required data from the backend to the client, but it depends of you infrastructure and you concurrent users.
Example 1:
You have a web app with +5K concurrent users, in this case is better handle all the huge stuff at frondend side or you will need to spend a lot of money in your backend hardware.
Practical case:
Users POST a new comment in a blog page. You sanitize the text string at the backend and put it at you preferred datastore... But JUST respond with a simple json like {"status": "ok"}. If the frond end recive this, modify the DOM with the text string that the client sent to the backend in the POST stage, but not send again all the HTML with this (for example) 500 characters comment.
If server responds with {"status":"error"}, modify the DOM to let the user know what's the problem about his comment (more specified json message {"status":"error", "data":"you comment is bigger than 500 chars"})
Problems:
You need extra frontend code to handle these situations in the client side. So this "maybe" will inpact on the user the 1st time that it visits your page.
Pros:
Less hardware costs
Overall less server response times.
More user interactive website modeling only certain parts of the DOM at any moment.
...
Example 2:
You have a simple page with low concurrent users. Then you choose. Let you backend to handle everything? Or keep working with json responses?
I always use the 1st example. Hope this helps in your question.
I think the preferred method would be to set up a second route from express to specifically render JSON, then use angular's $http method to get that data and use it in your controller. If you want to do it with a single route, you can pass the JSON data as a string to your view on the server-side, but it might get a little unruly.
// app.js
...
partnerList: JSON.stringify(partnerList);
...
// index.jade
div(ng-repeat="item in partnerList")
p {{ item.name }}
button(type='remove', ng-click="sub(item._id)")
...
script.
app.controller('view1Ctrl', function($scope, $http) {
$scope.partnerList = JSON.parse(#{partnerList});
...
EDIT To use the JSON string example, you would have to render using the Unbuffered Code syntax. But I'm not sure how you would do that inside a script. block. To instead go the route of serving JSON separately, change your server routes to this:
var Partner = require('../model/partners');
router.get('/', function (req, res) {
res.render('campaign');
});
router.get("/partner-list", function(req, res) {
Partner.find({}, function (err, partnerList) {
if (err) throw err;
res.json({ partnerList: partnerList });
});
});
Then your angular code will query that /partner-list path with $http.get().
script.
app.controller('view1Ctrl', function($scope, $http) {
$http.get("/partner-list").then(function(result) {
$scope.partnerList = result.data.partnerList;
});
...
});

Node.js: Returning proper JSON from mongoose query

I have this express application with mongoDB as the database and handlebars as my server-side templating engine. I am not using AngularJS or Ajax in my application.
In one of the routes, I have to render the page as well as send over a json file from the database. However, I am not able to achieve this.
Here is code snippet the my route:
router.get('/disks', function(req, res, next) {
places.find({"category": "disks"}, function(err, disks){
if(err){
throw err;
}
res.render('disks',
{
'risime': JSON.stringify(disks)
});
console.log(disks); // PROPERLY LOGS TO THE CONSOLE
});
});
In the hbs, I am trying to capture it, but I don't even think that it is JSON.
Here is how it gets logged in the client side:
[{"_id":"5704630a7d4cd367f8dsdce7","name":"Seagate",:"This awesome Hard disk",","categories":["SDD","256GB"]}]
What is the issue and how do I resolve it?
It's handlebars that "html escapes" your string (which is what you normally want).
if you don't want that, you can use the "triple-stash" notation, like this:
{{{risime}}}
You can read about this here: http://handlebarsjs.com/#html-escaping
I think you need to add this before render:
res.type('application/json');
The client will know this is a JSON, not a HTML or a plain text and it will be shown correctly.
I hope my answer will help you.

Confused about request path being sent to my Express server from AJAX

I have a basic setup for Node.js Express server
I am trying to serve html files using res.sendFile, using this route handler:
router.get('/:run_id/:test_num',function(req,res,next){
var runId = req.params.run_id;
var testNum = req.params.test_num;
res.sendFile(path.resolve('results',runId,testNum),{
maxAge:'58h'
});
});
in my app.js file, I have this middleware
app.use('/results', require('./routes/results'));
the problem is that the request is being routed like so:
pathname: '/results/results/1450830953375/test6.txt',
path: '/results/results/1450830953375/test6.txt',
href: '/results/results/1450830953375/test6.txt'
so the problem is that it is /results/results/ instead of just /results
I am using RequireJS and the module that contains the data of the files to be request looks like this:
define('SumanTestFiles',function(){
return new Object(["results/1450830340344/test5.txt","results/1450830340344/test6.txt"]);
});
and then I loop over each file path and request it from the server using jQuery/AJAX:
define(['SumanTestFiles'],function(stf){
stf.forEach(function (testPath) {
$.get(testPath).done(function (msg) {...
so you can see that the testPaths have not been tampered with, they without a doubt simply "results/1450830340344/test5.txt", or the like.
so my question is, why does the path show up on my server with two adjacent 'results' string instances in the path?
It does not make a lot of sense, because the request should just be
/results/1450830953375/test6.txt
not
/results/results/1450830953375/test6.txt
anyone have any ideas? thanks
This is new to me, since I fairly new to web development
The short answer is that instead of this:
define('SumanTestFiles',function(){
return new Object(["results/1450830340344/test5.txt","results/1450830340344/test6.txt"]);
});
I need to do this
define('SumanTestFiles',function(){
return new Object(["/results/1450830340344/test5.txt","/results/1450830340344/test6.txt"]);
});
otherwise the AJAX request path to my server will be relative to the URL in the searchbar, instead of absolute. Holy crap that was confusing.

Angular ngInit formatting

I'm building a MEAN app and I'm trying to pass in data from the server-side into the angular application and I've read that this is possible with the use of ngInit but I'm having a lot of trouble with getting it to work.
My Express route is set up as follows:
app.get('/dashboard', Auth.ensureAuthenticated, function (req, res) {
res.sendfile('./app/views/admin.html', req);
console.log(req.user);
});
The console log message is there for production reasons so I can see the current authenticated user in the terminal.
Now when I try to pass req into ngInit and I'm getting tonnes of errors. If my body is set up like:
<body class="dashboard" ng-controller="DashboardController as dashboard" ng-init="active_user = {req.user}"> ... </body>
This causes angular to spit out:
It looks like you're sending a plain html file with res.sendfile(…) and expecting Express to interpolate a variable.
In order to do what you're asking you'll need to do some server-side templating. It looks like res.render('admin', {user: req.user}); will do the trick, assuming you've modified your admin view to be a proper template.

AngularJS unwanted Behavior when reloading page

I'm developing an Angular application with the MEAN stack, so suppose you got an express route that make a query to the databse, the results are sent in the response:
app.get('/api', function(req, res){
Todo.find({}, "", function(err,todos){
if (err)
res.send(err);
res.json(todos);
});
});
In the client-side:
Controller :
...
Todo.get().success(function(data){ //i got the service with the $http call
$scope.todos = data;
});
When I go to localhost:8080/#/api, I can see my partial and the data I requested.
The problem that I'm having is that if I omit the hashtag, i don't see the partial, I only see the response data in JSON format.
I also tried to use html5 mode, but if I reload I got the same behavior.
Any ideas on how can I avoid this behavior??
Anything after the # isn't sent to the server. So when you go to localhost:8080/#/api, expressjs just sees a request to / and returns the AngularJS template. AngularJS then routes the browser page using the /#/api, which called the Todo.get() and (I assume) makes a call to localhost:8080/api, returning the data from the DB.
That's why you only get the data when you omit the hash and when you use html5 mode.
I would suggest changing your API call to:
/api/todos - return data from the db
And change your AngularJS route to just use:
/todos - show the partial and data requested

Categories

Resources