node.js and expressjs render a template with a URL param - node.js

Currently a user comes to my register page with an invitation ID
Example: http://www.mysite.com/user/register/50e203eb4d37bdfd22000042
The page loads and the form loads etc.... all is great. I then do some back end validation and if validation fails I call the res.render with the messages and the form data:
res.render('user/register', {
messages: messages
, form: form
});
It all works as expected however when the render occurs it puts the user back to:
http://www.mysite.com/user/register (its missing the invite_id)
How can I pass along a URL param with the res render?
If I do:
res.render('user/register/50e203eb4d37bdfd22000042', {
messages: messages
, form: form
});
Its actually looking for that 50e203.... file and giving me the 404 not found
Thanks!

Are you perhaps confusing res.render() with app.get()? It looks like you're trying to specify a route in that second example: res.render('user/register/50e203eb4d37bdfd22000042'... - but res.render doesn't specify routes, you need app[METHOD] for that, where app is an express instance.
In order to handle a GET request to /user/register/someinvite, use:
app.get('/user/register/:invitation', function(req, res, next) {
// in here you can access the invitation id with req.params.invitation
res.render('user/register');
});

Related

What to do when NodeJS rest api is sendind status 404 while using parameters?

I am having a strange problem while writing my api. I am using Nodejs and express. The problem occurs when i try to use GET with parameters.
This is my routes code
router.get('/addFriends/:email', (req, res, next) =>{
const email = req.params.email;
UserSchema.find({email: email}, { "friendsPending.emailSender": 1, _id : 0}, (err, data) =>{
if(err){
res.status(404).send(err);
}else{
res.status(200).send(data[0]);
}
});
});
This is my call in Postman : /users/addFriends?email=a
When running this call, server returns 404 status. It happened even when i tested it with another get call.Any comments are appriciated, however other POST and GET calls work normally (they use body not parameters). Thanks
You mixed query params and url params. To make your example working, you need to use /addFriends/my-email#gmail.com instead of /users/addFriends?email=a.
If you need to send emails via query params (everything after ?) use req.query in your controller instead of req.params.email.
This route definition:
router.get('/addFriends/:email', ...);
expects a URL that looks like this:
/addFriends/someEmail
And, you would use req.params.email to refer to the "someEmail" value in the URL path.
Not what you are trying to use:
/addFriends?email=a
If you want to use a URL such as (a URL with a query parameter):
/addFriends?email=a
Then, you would have a route definition like this:
router.get('/addFriends', ...);
And, then you would refer to req.query.email in the route handler. Query parameters (things after the ? in the URL) come from the req.query object.
In Express, route definitions match the path of the URL, not the query parameters.
when you use /addFriends/:param you force the router to match any request tha have a part in path as :param.For example:
/users/addFriends/toFavorates // will **match**
/users/addFriends/toFavorates?email=a // will **match**
/users/addFriends?email=a // will **not** match
if you want to make :param as optional part of url path put a ? after it
/addFriends/:param?
it will tell express route that :param is an optinal part. See this question
express uses path-to-regexp for matching the route paths. read the documentation for more options

Make data persist in form using mongodb node express

Hi I can connect to and store to mongodb using mlab but I can't get the data in the form to remain on refresh.
The form takes in user input from input-boxes.
Any help would be great.
Thanks
If being able to get the same form data for all the requests (no matter where they are made from)is what you want, then a possible workaround could be as follows:
1) Store the initial form data(probably empty) in the database, get the ObjectId and hard code it in your code, this way all the updates would be made to that specific MongoDB document only.
2) The form route (below one) should do nothing except for serving the file which has the form
app.get('/form1', function (req, res) {
res.sendFile(__dirname + '/public');
//record.find({"_id": ObjectId("MLAB ID")})......dont do this
});
3) There should be another route that sends form data
app.get('/getdata', function(req, res) {
record.find({"_id": ObjectId("MLAB ID")}, function(err, doc) {
res.send(doc)
})
});
4)The static file that you send to the client should have a javascript function such that it asks for the form data as soon as your window loads and then sets the value of input elements from that data recieved:
window.onload = function() {
//make a GET request to /getdata to get form data....store it in obj
//then set the input values
document.getElementById("yourchoice").value = obj.yourchoice;
//and set the value of other input fields ....in similar amnner
}
5) The POST request you make should update that specific document( findOneAndUpdate?? )
Disadvantage of this method:
For one operation we request a file from server and then another request to get form data, so two requests for one operation, since we cannot use both res.sendFile() and res.json() together...one way to get around this is to hide the form data as well in the HTML document using a template engine. More about this can easily be found. Anyways the above method does solve your purpose.
I hope I correctly understood the problem statement.
Happy coding!!
Edit:Although the above mentioned points are explainatory, I have written a sample snippet at : https://pastebin.com/AvgVyx7b
It works perfectly fine

JadeJS and pre written form values at re-rendering views

I'm using Node/Express and Jade to build and App.
I have a POST route that sanitize and validate form input and then save this to a MongoDB.
If this form input is'nt validated, the route will throw and error and the error handler will re-render this same page...
And here come the problem. In this re-render and want the form values be pre written and ready to be corrected by the user... I don't want a clean form where the user has to re-write everything.
I have tried to submit the req.body (sanitized) data to the re-rendered page, which works.
But if try to use this data in my Jade view, Node will output and error when this req.body data is not defined... Like when you enter this page for the first time, and have'nt entered any wrong inputs yet.
How do i solve this in a good way?
edit - Without a code sample I'm not sure if my example is more or less than you need.
If you render the form template immediately within the the form's POST request handler, you probably don't need to involve req.session. Just save the appropriate locals and render your template.
If you must redirect or otherwise need to have the values available across multiple requests, you can save them in req.session as shown below.
Either way make sure your Jade template handles all cases; in my example I test if(locals.savedValues) to decide whether to write defaults or saved values into the form.
Finally if the error is not jade related please paste that error.
Use req.session to save the values. Set up a locals variable to represent the saved values or null before you render the form.
app.get('/form', function(req, res){
res.locals.savedValues = req.session.savedValues || null;
res.locals.savedErr = req.session.savedErr || null;
res.render('form');
});
app.post('/form', function(req, res){
var values = {
name: req.body.name,
email: req.body.email,
};
validateForm(values, function(err, processed){
if(err){
req.session.savedValues = processed;
req.session.savedErr = err;
// req.session.savedValues = values, if you dont want to propose changes
res.redirect('back');
} else {
delete req.session.savedValues;
delete req.session.savedErr;
res.redirect('/success');
};
});
});
In your jade template, handle both cases:
if(locals.savedErr)
span.error=locals.savedErr
form(action='form', method='post')
if(locals.savedValues)
input#name(type='text')=locals.savedValues.name
input#email(type='text')=locals.savedValues.email
else
input#name(type='text')
input#email(type='text')

How to get req and res object of Expreejs in .ejs file

I am trying to use Express js with .ejs views.
I want to redirect my page to some another page on any event let say "onCancelEvent"
As per Express js documentation,I can do this by using res.redirect("/home");
But I am not able to get res object in my ejs file.
Can anyone Please tell me how to access req and res object in .ejs file
Please help.
Thanks
Short Answer
If you want to access the "req/res" in the EJS templates, you can either pass the req/res object to the res.render() in your controller function (the middleware specific for this request):
res.render(viewName, { req : req, res : res /* other models */};
Or set the res.locals in some middleware serving all the requests (including this one):
res.locals.req = req;
res.locals.res = res;
Then you will be able to access the "req/res" in EJS:
<% res.redirect("http://www.stackoverflow.com"); %>
Further Discussion
However, do you really want to use res in the view template to redirect?
If the event initiates some request to the server side, it should go through the controller before the view. So you must be able to detect the condition and send redirect within the controller.
If the event only occurs at client side (browser side) without sending request to server, the redirect can be done by the client side javascript:
window.location = "http://www.stackoverflow.com";
In my opinion: You don't.
It is better to create the logic that determines the need to redirect inside some middleware that happens long before you call res.render()
It is my argument that your EJS file should contain as little logic as possible. Loops and conditionals are ok as long as they are limited. But all other logic should be placed in middleware.
function myFn( req, res, next) {
// Redirect if something has happened
if (something) {
res.redirect('someurl');
}
// Otherwise move on to the next middleware
next();
}
Or:
function myFn( req, res, next) {
var options = {
// Fill this in with your needed options
};
// Redirect if something has happened
if (something) {
res.redirect('someurl');
} else {
// Otherwise render the page
res.render('myPage', options);
}
}

How to apply post redirect and get pattern in node.js?

I am testing with a very simple application in node.js where I create and save an application. I show the post form with the newPost function and I receive the post with the data in the savePost method. In the latter one I do a validation (with iform module) and I want to go show again the same page as before but filling the form with the data sent by the user and also with the errors found.
I have a similar code like this one. In it I render the same jade page if I find any error. It works though I want to apply the pattern redirect and get there as I don't want to send again the post request when the user presses F5.
So, how is the usual way to make a post redirect and get from the post method passing them all the parameters I have received adding the errors? Is there any module which can help to do so?
var prepareObject = function(req, res){
var errors = {};
if('iform' in req){
errors = req.iform.errors;
}
return {title: 'Nuevo Post', body:req.body, errors: errors};
};
// mapped as /newPost (type GET)
exports.newPost = function(req, res){
//show form to create post
res.render('newPost', prepareObject(req, res));
}
// mapped as /savePost (type POST)
exports.savePost = function(req, res){
if(req.iform.errors) {
//there are errors: show form again to correct errors
res.render('newPost', prepareObject(req, res));
}else{
//no errors: show posts
res.redirect('/posts');
}
}
You can redirect to GET "/newPost" instead of rendering the "newPost" template.
To have autocomplete working, you may either add the data to the redirect query (faster) and render it, or add the data to the session (don't forget to delete it after rendering), but the later option requires a session store.

Resources