Recently I started learning node js and I have a question.
Before rendering a page I want to make 2 or more request to mongodb and then render page.
Currently I have sth like this:
exports.index = function(req, res) {
Manga.find({}, function(err, data){
if(err) console.log('error in getting some mangas');
res.render('index', {data: data, session: req.session.userId });
});
};
But I also want to get data of session user before rendering. How can I do that?
First you need to save data, about user, in to session object and then call:
res.render('index', {
data: data,
sessionID: req.session.userId,
email:req.session.emaill,
user_name: req.session.user_name
})
with express:
app.get("/",function(req,res,next){
Manga.find({}, function(err, data_from_db){
if(err) console.log('error in getting some mangas');
// set user data from DB in every request
req.session.user_data=data_from_db
next()
})
})//get
.......
.......
app.get("/index",function(req,res){
res.render('index', {
data: data,
sessionID: req.session.userId,
email:req.session.emaill,
user_name: req.session.user_name
})
})//index
Or you can use global functions and async filters from template engine to request directly user data if page need this data. https://mozilla.github.io/nunjucks/api#custom-filters
Related
I am in the middle of a personal project to practice web development better to understand the ins and outs of web development, but I have run into a brick wall. In this personal project, I am creating a profile page. I have successfully linked the MySQL database to my server js file because I can import data to the table, but I am stuck trying to export the data to an ejs file.
I did the following to export the code, but I cannot even call the data because I cannot have SQL locate any entries from login.
app.get('profile', function (req, res) {
console.log("Inside Get Profile");
connection.query('SELECT * FROM ACCOUNTS WHERE PrimaryEmail = ? ', [req.body.email], function(error, results, fields) {
if (error){
console.log("Error");
console.log(error);
} else if (results.length > 0) {
console.log("Data From Get Profile")
console.log(results);
res.render('profile', { data: results });
}})});
So I did the following in an attempt to resolve my issue, which could work, but I am in the matter of pulling the data into the ejs file.
function userProfile(req, res, next){
console.log("Inside userProfile Function");
connection.query('SELECT * FROM ACCOUNTS WHERE PrimaryEmail = ? ', [req.body.email], function(error, results, fields) {
if (error){
console.log("Error");
console.log(error);
next();
} else if (results.length > 0) {
console.log("Data From userProfile Function");
console.log(results);
res.render('profile', { data: results });
next();
}})};
I would call the function at login after.
app.post('/login', userProfile, passport.authenticate('local', {failureRedirect:'/login-faliure', successRedirect:'/dashboard'}));
Any advice on how to get MySQL data to display certain information for the profile page would suffice!
Thank you for your time!
Looks like you've implemented the correct code for passing the parameters to EJS (the first code snippet you showed), so there's no reason something like this wouldn't work.
Hello, <%=data.name%>!
This would be because you passed the user data under "data" here:
res.render('profile', { data: user });
I found out that I had two app.get(‘profile’) method and now the page loads with no error after removing the un-needed one. The next thing I had to do was add the code below after “results.length > 0” and my data would start to show.
user={id:results[0].ID, email:results[0].PrimaryEmail, hash:results[0].EncryptHash, password:results[0].EncryptPassword};
console.log(user);
res.render('profile', { data: user})
The existing code was written as MySQL query and I am now working on converting it to Mongoose query.
I need to get five data sorted by the most recent subscription year from the main page.
The existing code brought this result value into an array. And data was delivered through pug view, and Mongoose seems to bring the result value of Object. In this case, I wonder how to deliver the data through Pug view.
I checked importing data from the terminal to the console.log, but an error called 'Error [ERR_HTTP_HEADERS_SENT]: Cannot set heads after they are sent to the client occurs and no data is passed to the pug. I wonder why this problem occurs.
[MySQL Query]
router.get("/", function (req, res, next) {
// Main page Profile Data Process
db.query(`SELECT * FROM user ORDER BY registerDate DESC LIMIT 5`, function (
error,
data
) {
// Log Error
if (error) {
console.log(error);
}
res.render("main", {
dataarray: data,
_user: req.user,
url: url
});
});
});
[Mongoose Query]
router.get("/", function (req, res, next) {
let dataarray = [];
let userData = db.collection("user").find().limit(5).sort({
"created_at": -1
});
userData.each(function (err, doc) {
if (err) {
console.log(err);
} else {
if (doc != null) {
dataarray.push(doc)
}
}
// console.log(dataarray.login)
console.log(dataarray);
res.render("main", {
dataarray,
_user: req.user
})
});
});
[pug file]
each profile in dataarray
.col-lg-4
img.rounded-circle(src=`${profile.avatar_url}` alt='Generic placeholder image' width='140' height='140')
h2=`${profile.login}`
p=`${profile.bio}`
p
a.btn.btn-secondary(href=`/${profile.login}` role='button') View details »
You are sending the request in multiple chunks, node/express uses one request and one response.
Cannot set heads after they are sent to the client
Is the error that happens when the res.render is called the second time. At this point, the one request has already left the node/express process and this is tell you that you're trying to violate the one request/one response paradigm.
This is the part of your code where you can see why this happens.
router.get("/", function (req, res, next) {
let dataarray = [];
let userData = db.collection("user").find().limit(5).sort({
"created_at": -1
});
userData.each(function (err, doc) {
This part of your code will try to send a response for each item in your resultset.
Something like this will work properly (I didn't test it):
router.get("/", function (req, res, next) {
db.collection("user").find().limit(5).sort({ "created_at": -1 }, function(err, userData){
res.render("main", {
dataarray: userData,
_user: req.user
})
});
});
In other words, only one res.render is required and pass the entire result set into that.
I have two separate app.get routes that render "/" and contain mongoose find{} methods, which relates to two mongodb collections. I then have corresponding post routes that redirect/post to "/" with the data I entered on the forms.
Depending on the form I use (devportals/new or writingportals/new) to submit my data, I would like it to use the correct app.get to find the data and then populate my index.ejs file to display the new entry.
When I submit my post, it always defaults to the devportal.find{} GET route at the top even though I submitted my update to mongodb through the writingportals form.
app.get("/", function (req, res){
devportal.find({}, function(err, newDevPortal){
if(err){
console.log(err);
}else{
res.render("index",{newDevPortal: newDevPortal});
}
});});
app.get("/", function (req, res){
writingportal.find({}, function(err, newWritingPortal){
if(err){
console.log(err);
}else{
res.render("index",{newWritingPortal: newWritingPortal});
}
});
});
app.get("/portals/writingportals/new", function(req, res){
res.render("portals/writingportals/new");
});
app.get("/portals/devportals/new", function(req, res){
res.render("portals/devportals/new");
});
app.post("/", function(req, res){
var wpTitle = req.body.writingtitle;
var wpUrl = req.body.writingurl;
var wpImageUrl = req.body.writingimageurl;
writingportal.create({title: wpTitle, url: wpUrl, imageurl: wpImageUrl}, function(err, newWritingPortal){
if(err){
console.log(err);
}else{
res.redirect("/");
}
});
});
app.post("/", function(req, res){
var devTitle = req.body.writingtitle;
var devUrl = req.body.writingurl;
var devImageUrl = req.body.writingimageurl;
devportal.create({title: devTitle, url: devUrl, imageurl: devImageUrl}, function(err, newDevPortal){
if(err){
console.log(err);
}else{
res.redirect("/");
}
});
});
I have two separate app.get routes that render "/"
Your endpoints do not render "/", they get triggered based on the request uri, which in your case is "/".
Next, you cannot have two endpoints with the same route and same type of request, this is true with any web server. So in your case, you have two endpoints defined for GET requests to '/'. There is no way for your code to understand the difference between those two routes, so it will always hit the first one it finds.
Finally I'll add that for your solution, you most definitely will want unique endpoints because you are taking a template with a data model and sending back markup.... basically an endpoint for each page.
I will say that I'm not a huge fan of that approach. I think it makes life easier using a framework like react, then have every request to '/' return index.html with a reference to your react code... instead of the whole SSR deal.
However, for a lot of things, its simple to just use query parameters in the request. Here is an example where one endpoint is defined that will return all data from any collection through query parameters:
app.get('/api/collection', function(req, res) {
var collection = req.query.collection;
var _collection = db.collection(collection);
_collection.find({}).toArray(function(err, docs) {
if (err)
return res.status(500).send(err);
res.send(docs);
})
})
And then the request url would be GET -> /api/collection?collection=NAME_OF_YOUR_COLLECTION
I am registering a user and after successful registration I want alert something in client side. So, what I do in server side, after registration I'm sending a value "registered" then when it gets that value, my client side would know that user is registred but I don't know how to get that value in my client side.
router.post('/registration', function (req, res, next) {
var stud = {
username: req.body.username,
email: req.body.email,
password: req.body.password,
admin: 0
};
mongo.connect(url, function (err, db) {
assert.equal(null, err);
db.collection('user-data').insertOne(stud, function (err, result) {
assert.equal(null, err);
console.log('Student inserted');
db.close();
res.json('registred');
})
})
});
My client side code
$('.MyForm').on('submit', function(event){
event.preventDefault();
$.ajax({
url: '/registration',
method: 'post',
success: function(response){
}
})
});
There is not very much because I don't know what to do next
All you still need to do is put the alert in the callback to the ajax request
success: function(response) {
alert('User registration succeeded!')
}
Since you're using HTTP protocol, why not use its cohesive response codes to indicate which action has happened? For example:
200 - user successfully created
400 - malformed input data
409 - one of unique user's model field has been already taken
And so on. Use method 'status' on response object to set appropriate return code. I assume that you are trying to create server with REST's rules in mind, therefore your endpoint should return freshly created entity on POST request.
mongo.connect(url, function (err, db) {
assert.equal(null, err);
db.collection('user-data').insertOne(stud, function (err, result) {
if(err) {
/* At this point, you may decide to check what error has been returned to decide which code will be returned*/
return res.status(400).json(err);
}
console.log('Student inserted');
db.close();
res.status(200).json(result);
})
})
On client side, code might be much more pleasant to eye after you would refactor it to use jQuery's ( since ver. 1.5.1 )'Promise API'
$.ajax({
url: 'http://localhost:8000',
method: 'POST'
})
.done(function( data ) {
})
.fail(function (reason) {
})
Using ReactJS, Redux, Webpack, Node.js and Express with MongoDB, I am following the tutorial https://github.com/vasansr/mern-es6 and trying to integrate it into my project. First, I am trying to make a POST request to the server I created. And it gets a response with a success and no error is logged. Yet inside the server POST API, it does not log console.log('Req body', req.body);, and in terminal I checked to see if the database has been created with mongo -> show dbs but it is empty.
Could it be that something is intercepting the request from the server? What could be the issue?
This...
app.use('/', function (req, res) {
res.sendFile(path.resolve('client/index.html'));
});
comes before:
app.post('/api/users/', function(req, res) {
//...
});
Since it's app.use the POST /api/users will still hit that middleware, and res.sendFile ends the request/response. You'll probably see that your post is getting back the client HTML.
Try moving your client HTML endpoint to the end of your middleware, just before the error handlers if you have them. That way, it'll only get used if none of your API endpoints match. Or if you want just GET / to return the HTML, change use to get:
app.use(webpackDevMiddleware(compiler, {noInfo: true, publicPath: config.output.publicPath}));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('dist')); //where bundle.js is
app.use(bodyParser.json());
app.post('/api/users/', function(req, res) {
console.log('Req body', req.body);
var newUser = req.body;
db.collection('users').insertOne(newUser, function(err, result) {
if(err) console.log(err);
var newId = result.insertedId;
db.collection('users').find({_id: newId}).next(function(err, doc) {
if(err) console.log(err);
res.json(doc);
});
});
});
app.get('/', function (req, res) {
res.sendFile(path.resolve('client/index.html'));
});
app.post('/api/users/', function(req, res) {
console.log('Req body', req.body);
var newUser = req.body;
db.collection('users').insertOne(newUser, function(err, result) {
if(err) console.log(err);
var newId = result.insertedId;
db.collection('users').find({_id: newId}).next(function(err, doc) {
if(err) console.log(err);
res.json(doc);
});
});
});
I have a small comments about this code, for if(err) console.log(err); i think you should change to if(err) return console.log(err);.
For error case, i think you need return, otherwise the below part will be excuted, and there will report some error.