Why is req.params returning 'undefined'? - node.js

I have a simple comments app which enables the user to enter a comment into the system via a form and these are then logged onto a list on the bottom of the page.
I wanted to modify it so that a user could click a comments title once it is created and it would load up the associated content that goes with that comment.
I have modified my route in the app.js to lookup the :id:
And have also modified my main Show.js route to use the id as an argument in a findOne command to locate the comment.
I have also put in a console.log() command to log out the req.params.id
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Comment = mongoose.model('Comment', Comment);
router.get('/', function(req, res) {
Comment.findOne({ id: req.params.id }, function(err, comment){
console.log(req.params.id)
});
});
module.exports = router;
However, all I am getting back is an undefined message in my terminal.
If I place the console.log() directly in my app.js, I get the id logged as intended.
app.use('/:id', function(req,res) {
console.log(req.params.id)
});
Am I missing something in my route that is stopping my from getting the id parameter?

You need to specify the :id in your get route, like this:
// GET /1 -> print 1
router.get('/:id', function(req, res) {
console.log(req.params.id);
});
// GET /foo/1/bar/2 -> print 1, print 2
router.get('/foo/:id1/bar/:id2', function(req, res) {
console.log(req.params.id1);
console.log(req.params.id2);
});

You need to pass {mergeParams: true} when calling your router in the router page
var router = express.router({mergeParams: true})
this will pass the parent parameters to the child.

Related

node.js express - how to pass POST body params back to original form to re-populate on invalidation?

I have a sign up form that I want to re-populate with the user entered data when the form is submitted but has errors in them. I am using express-validator and connect-flash to check / show error messages. I can't seem to figure out a way to pass the original values back to repopulate the field.
Here's my route:
router.post('/edit',
// Input validation
function(req, res, next) {
req.checkBody('username', 'Username cannot be empty').trim().notEmpty();
var errors = req.validationErrors(true);
if (errors) {
req.flash('validation', errors);
res.redirect('/vendor/edit/'));
} else {
//Add to DB
}
});
Here is where I either load the original form, or where it gets redirected to show the form with error messages. :
router.get('/edit', function(req, res) {
res.render('vendor_edit', {
validation: req.flash('validation')[0],
error: req.flash('error')[0],
});
});
However, the form is blank when it gets redirected since my template doesn't have the original values, or I don't know how to access them if they are naturally passed? - I am trying to render in PUG.
This is made possible via this post:
How do I redirect in expressjs while passing some context?
For the lazy, here is the copy and paste of the code from the above link, it worked like a charm for me.
var express = require('express');
var jade = require('jade');
var http = require("http");
var app = express();
var server = http.createServer(app);
/////////////
// Routing //
/////////////
// Move route middleware into named
// functions
function homeCtrl(req, res) {
// Prepare the context
var context = req.dataProcessed;
res.render('home.jade', context);
}
function categoryCtrl(req, res, next) {
// Process the data received in req.body
// instead of res.redirect('/');
req.dataProcessed = somethingYouDid;
return next();
// optionally - Same effect
// accept no need to define homeCtrl
// as the last piece of middleware
// return homeCtrl(req, res, next);
}
app.get('/', homeCtrl);
app.post('/category', categoryCtrl, homeCtrl);

How to send a variable from one router to another

Please, I wand to send a variable from login.js to dashbaord.js using node.js.
This is my dashboard.js:
var express = require('express');
var router = express.Router();
var Firebase = require('firebase');
var login = require('./login');
var user = login.userId;
var admin = require("firebase-admin");
var login = require('./login');
/* GET home page. */
router.get('/', function(req, res, next) {
console.log(user) // this return an undefine
res.render("pages/dashboard");
});
module.exports = router;
Thanks in advance.
The code in routes only runs when the URL pattern is hit. So in the code below the value in user will be printed out every time the "/" gets hit but you only initialized user once.
router.get('/', function(req, res, next) {
console.log(user) // this return an undefine
res.render("pages/dashboard");
});
The line for var user = login.userId; is only set once when your main express app is booted up. That is why it's coming back as undefined. But you shouldn't be passing user information from module to module this way, thats what sessions are for.
Sessions & UserIds
If you want to get the userId you should be storing it in the users session or in a cookie then you can pull it out of the request object. Any data that is specific to a user you can retrieve from your database using their userId in the session. With express theres no built in support for sessions but you can npm install middleware that will take care of this for you so that you can then write.
router.get('/', function(req, res, next) {
console.log(req.session.userId)
res.render("pages/dashboard");
});
Environment Variables
If you need to pass configuration settings around across multiple modules you can use
process.env.${propertyName} for example process.env.cat = "Henry". But that is for things you set once that are the same for all users.

ExpressJS Router is not handling root routes

UPDATE 2: I just noticed that if on the app file I change the line:
app.use('/', home);
to:
app.use('/anything', home);
then all of the sub routes "roots" work fine.
UPDATE 3: I just realized something else. A method on the home.js file that I did not originally include below since I didn't think was relevant turns out to be the cause of the problem.
router.get('/:adventureId', (req, res) => {
var data;
//Irrelevant content that sets data as a JSON object.
res.json(data);
});
Turns out that every single sub route "root" is passing through here and since on the other routes adventureId is undefined then data is just an empty JSON object.
So the real question is: If this router bound to "/" and the other "roots" are bound to "/adventure" and "/test" why are all of them going through "/:adventrueId"?
I have a very simple ExpressJS application on which all of the "roots" in each and every single route other than home are not being handled and they always display an empty JSON object on the page.
In some posts it was mentioned that it could be a caching issue since these routes always return a 304 status, but I've tried doing an "Empty cach and hard reload" on Chrome and even with the 200 status I still get a blank page with an empty JSON object displayed on it. I tried it with MS Edge and got the exact same behavior.
Here's what I have:
On my app file
var app = express();
var home = require('./routes/home');
var adventure = require('./routes/adventure');
var test = require('./routes/test');
app.use('/', home);
app.use('/adventure', adventure);
app.use('/test', test);
On home.js file:
var express = require('express');
var router = express.Router();
router.get('/', (req, res) => {
console.log("This works fine with http://localhost:3000.");
res.render('home');
});
router.get('/:adventureId', (req, res) => {
var data;
//Irrelevant content that sets data as a JSON object.
res.json(data);
});
module.exports = router;
On the adventure.js file:
var express = require('express');
var router = express.Router();
router.use('/:id', (req, res) => {
console.log("This works fine with http://localhost:3000/adventure/5.");
next();
});
router.get('/:id', (req, res) => {
console.log("This works fine with http://localhost:3000/adventure/5.");
res.render('adventure');
});
//I've also tried putting this before the other routes and the result is the same.
router.get('/', (req, res) => {
console.log("This is never written in the console with http://localhost:3000/adventure.");
res.send("This is never rendered in the page.");
});
On the test.js file:
var express = require('express');
var router = express.Router();
router.use('/', (req, res) => {
console.log("This is never written on the console with http://localhost:3000/test.");
res.send("Hello from the test root route");
});
module.exports = router;
In the ExpressJS Router documentation and every single blog and example I've found it says that this is how it should work so I am really at a loss here.
Thank you.
If this router bound to "/" and the other "roots" are bound to "/adventure" and "/test" why are all of them going through "/:adventrueId"?
Because Express doesn't match routes based on which one matches best, it matches on which one matches first.
In your case, the route /:advertureId was declared before the routes for /adventure or /test. And /adventure and /test both match /:advertureId, so the handler for that route is called.
If you want to prevent this, declare more specific routes first:
app.use('/adventure', adventure);
app.use('/test', test);
app.use('/', home);
After much going around, several updates on the question and banging my head against the keyboard I finally understood what the problem is:
By having the routers set up like this:
app.use('/', home);
app.use('/adventure', adventure);
app.use('/game', gameService);
app.use('/test', test);
and on the "home" router having this method signature:
router.get('/:adventureId', (req, res) => {
var data;
//Irrelevant content that sets data as a JSON object.
res.json(data);
});
Every single sub route "root" was being interpreted as the parameter of the previous method so:
/adventure
/test
/anything
would be handled as:
adventrueId = adventrue
adventureId = test
adventrueId = anything
The solution was to do this:
app.use('/adventure', adventure);
app.use('/game', gameService);
app.use('/test', test);
app.use('/', home);
And now everything works.

How to get parameters using express in node

I am certain that this is super easy, but I can't for the life of me figure out why this does not work.
So trying to write an application where a user can search, gets a link, and if clocked it calls a second route, passing a variable while it is at it. Sounds simple, so thought I.
The idea is that each link generated gets a link like "localhost:3000/getcan/:[id]"
So for our example, I am trying to get 22 into a variable if I try to go to webpage
"localhost:3000/getcan/:22"
To set up the route, I set the following in app.js
app.use('/getcan/:*', getcan);
This seems to work, and if I put anything that calls /getcan/: I go to the right route.
The route it self looks as follows
var express = require('express');
var router = express.Router();
/* GET getcan page. */
router.get('/', function(req, res, next) {
var canid = req.params.canid;
console.log("Got the following id " + canid)
res.render('getcan', { title: 'ResourceEdge', reqcan: canid });
});
module.exports = router;
I think the problem is with router.get('/' but if I make any changes (tried get('/getcan/:canid) it all blows up with a 404.
Any pointers?
Change app.use to:
app.use('/getcan', getcan);
And your router to:
/* GET getcan page. */
router.get('/:canid', function(req, res, next) {
var canid = req.params.canid;
console.log("Got the following id " + canid)
res.render('getcan', { title: 'ResourceEdge', reqcan: canid });
});
Then call your route using: http://localhost:3000/getcan/22

How to pass parameter to routes?

I am using Nodejs .
Server.js
app.get('/dashboard/:id', routes.dashboard);
Routes / index.js
exports.dashboard = function(req, res){
}
I want to be able to pass the 'id' variable from app.js to the dashboard function . How do I go about doing this ?
Assuming ExpressJS, you shouldn't need to pass it.
For each parameter placeholder (like :id), req.params should have a matching property holding the value:
exports.dashboard = function (req, res) {
console.log(req.params.id);
};
Though, this assumes the requested URL matches the route by verb and pattern.
Just ensure that your GET call from the client is something like this: /dashboard/12345.
12345 is the id you want to pass to dashboard.
So, you can access it like this in server:
exports.dashboard = function(req, res){
var id = req.params.id;
console.log('ID in dashboard: %s', id);
}

Resources