As part of a generic get route in an express application, I want to send two flash messages with express-session and connect-flash. This all works except that req.flash does not save before the page is rendered. As a result, the flash messages do not show until the user loads another page or the same page again.
The code for the last function in the route:
Post.countDocuments().exec(function(err, count){
if(err) {
console.log(err);
res.redirect("back");
}
req.flash("success", ["It's working", "Hallelujah!"]);
req.flash("error", ["Uh oh!", "We have a problem..."]);
res.render("index", {posts: allPosts, dates: dates, current: pageNumber, pages: Math.ceil(count / pageLimit), showing: showing, total: count});
});
and here's the code for one of the flash message templates (ejs):
<div class="flash flash-success">
<div class="flash-header">
<span class="flash-title flash-title-success"><i class="fas fa-check"></i> <%= success[0] %></span>
<span class="flash-close" onclick="return closeFlash(this);"><i class="fas fa-times"></i></span>
</div>
<hr class="flash-hr">
<div class="flash-body-success"><%= success[1] %></div>
</div>
I have tried using .exec() after req.flash to make the render statement run on completion but this didn't work and I've also tried req.session.save() with the render statement in a callback but this also failed.
The issue is not resolved by getting rid of one of the req.flash statements nor by only passing one string argument instead of an array of two.
The problem was that I had
app.use(function(req, res, next) {
res.locals.currentUser = req.user;
res.locals.error = req.flash("error);
res.locals.success = req.flash("success");
return next();
});
in app.js and so this middleware was run before the route had chance to set values for req.flash meaning that error and success were set to be empty.
I solved this by creating a function to save req.flash in res.locals just before rendering the page:
var toolsObj = {};
toolsObj.saveFlash = function(req, res) {
res.locals.error = req.flash("error");
res.locals.success = req.flash("success");
};
module.exports = toolsObj;
Related
I am using Express for routing and MongoDB for my simple Node blog app (I'm new and just learning) and I need to redirect to the home page if somebody enters the incorrect URL, whenever it attempts to redirect the program crashes.
Terminal Output:
Server started on 3000
Rendered homepage
events.js:174
throw er; // Unhandled 'error' event
^
TypeError: Cannot read property 'postTitle' of null at line 115
Router Params / Get
//=== DYNAMIC POSTS ROUTE ===//
app.get("/posts/:postId", function(req, res){
const requestedPostTitle = req.params.postId;
Post.findOne({postTitle: requestedPostTitle}, function(err, foundPost){
if (!err) {
//FAILS HERE IF INCORRECT URL IS ENTERED INTO BROWSER
const title = foundPost.postTitle;
const date = foundPost.postDate;
const content = foundPost.postBody;
/*res.send(foundPost.postDate);*/
res.render(`post`, {
title: title,
date: date,
content: content
});
} /*else {
res.redirect(`/`);
console.log(`404 ${requestedPostTitle} does not exist`);
} */
});
});
The program will only crash if I type in an incorrect URL, after that, none of my pages will reload (I'm assuming because of the (err) callback), I have to restart my server manually and everything works again, nodemon doesn't reset it when it fails.
root view:
<h1>HOME</h1>
<p><%= pageStartContent %></p>
<% posts.forEach(function(post){ %>
<div class="post-box">
<h3><%= post.postTitle %></h3>
<p class="date"><%= post.postDate %></p>
<p class="post-body"><%= post.postBody.substring(0,450) + "..." %></p>
Read More
</div>
<% }) %>
app.get("/posts/:postId", function(req, res){
const requestedPostTitle = req.params.postId;
Post.findOne({postTitle: requestedPostTitle}, function(err, foundPost){
if (!err && foundPost) {
//FAILS HERE IF INCORRECT URL IS ENTERED INTO BROWSER
const title = foundPost.postTitle;
const date = foundPost.postDate;
const content = foundPost.postBody;
/*res.send(foundPost.postDate);*/
return res.render(`post`, {
title: title,
date: date,
content: content
});
}
return res.redirect(`/`);
});
});
the code didn't work before (maybe) because you are checking if there an error and if not rendering post but this does not mean that the post was found, you need to check if foundPost is not null.
I am studying about express-validator.
'router.post' passes without the validation
I made form and password input in html.
<body>
<h1>Hello Guys!</h1>
<p>Fill in your id number.</p>
<form action="/yournumber/sub" method="POST">
<input type="password" name="password">
<button type="submit">Summit</button>
</form>
</body>
And that password call router.post
This is my router code.
but this post runs redirect regardless of the length of password.
How could I make correctly?
router.post('/yournumber/sub', (req, res, next) => {
req.check('password').isLength({min: 4});
var errors = req.validationErrors();
if (errors) {
req.session.errors = errors;
req.session.success = false;
console.log('error');
} else {
req.session.success = true;
console.log('suc')
}
res.redirect('/ab');
});
I don't know the req.check()-notation and can't find it in the official documentation, but:
The way I use this module is as an express middleware. You can check the snipped on the linked documentation. Here is your adapted code:
const validation = [
check('password').isLength({min: 4})
];
router.post('/yournumber/sub', validation, (req, res, next) => {
var errors = validationResult(req);
if (errors.isEmpty()) {
// valid
} else {
// not valid
}
});
As you can see, the validation-array is passed in as another handler for the route. It works the same way as your handler:
Check if the parameter is valid, as specified to the check()-function
If not, add information to the req-object
Call next() to get to either the next validation or your handler.
Then, when you want to check the results, use validationResult() (which you spelled wrong and called as a method of req instead of passing it to the method).
I am developing a web application using MEAN Stack and Angular 6. My schema has following values.
UserName: default,
ExtrudedHeight:250,
There is a button in html page. After I click the button I want to get values of the collection where the userName= default.
For that I created a get method in router,
//Get single value by userName
router.get('/:userName', function(req, res, next) {
alert(Came to router);
extrudedHeight.findOne({'userName': req.params.userName}, function (err, post) {
console.log(req.params.userName);
if (err) return next(err);
res.json(post);
});
});
service.ts
getExtrudedHeight(userName) {
return this.http.get('/extrudedHeight/' + userName, {
});
}
html
<div class="">
<button type='button' (click)="setDefaultValues()" class="btn btn-sm btn-rectangle btn-default text-case">Default Values</button>
</div>
component.ts
Class{
extrudedHeightValue = {};
ngOnInit(){
this.setDefaultValues();
}
setDefaultValues(){
this.extrudedHeightService.getExtrudedHeight("default").subscribe(data => {
console.log(data);
this.extrudedHeightValue = data;
});
}
}
My question is I have added an alert in the router but when I hit the button it does not show. Is that mean my routing is wrong?
I am getting following errors as well.
I want to send some session variable through response redirect in my ejs views
router.get('/contact', function (req, res) {
console.log(req.session.enquiry);
res.render('contact', {
enquiry: req.session.enquiry
});
});
I want to pass session data here:
router.post('/sendresponse', function(req, res) {
req.session.enquiry = 'sent message';
res.redirect('/contact');
});
And display it in my view like:
<div class="mail_form">
<% if (enquiry) { %>
<div class="alert alert-danger"><%= enquiry %></div>
<% } %>
</div>
Any idea how to achieve this ,and no i don't want to use flash or something else
I am new to Express and MongoDB. I created a small web app in Node.js and am using Express.js and Mongoose. I can succesfully create a user and have a user sign in but I am having trouble with a user being able to delete their account.
I have a user.js file in my routes folder which is where I am writing the code to signup, signin, delete, etc. Here is a link to the project on GitHub ( https://github.com/NicholasGati/shopping-cart-2 ). The button to delete a user's account is in views/user/edit.hbs. I put the button in a form. When I click the button, the user is not deleted and I am redirected to '/' for some reason. Note: '/:id' in my routes/user.js file becomes '/user/:id'.
Here is the code in the routes/user.js file for the delete method:
router.delete('/:id', isLoggedIn, (req, res, next) => {
User.findOneAndRemove({_id: req.params.id}, (err) => {
if (err) {
req.flash("error", err);
return res.redirect("/user/edit");
}
req.flash("success", "Your account has been deleted.");
req.logout();
return res.redirect("/shop/coffee");
});
});
Here is the form in views/user/edit.hbs:
<form action="/user/{{user.id}}" method="delete">
<div class="form-group">
<button type="submit" class="btn btn-danger">Delete Account</button>
</div>
</form>
Also, here is the isLoggedIn function:
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect("/");
}
Since you are new I think I should lead you to find the problem yourself:)
Make sure about form methods.
Make sure the route for user deletion is called.
If the markup doesn't seem right I am sorry cas I am using my phone to post this answer.
I had this exact same issue. I used an XMLHttpRequest from the client side in order to do this. I'm sorry I'm not experienced enough to explain why it worked this way and not from the node end, but it may have to do with form data being inherently designed to pass information, not delete information. In any case, try this solution.
In your client side code:
Your button code (form action shouldn't matter, and for that matter, the tag shouldn't either, since the logic is handled in the JS, but this is what I used):
<button id = "del-btn" class="btn btn-danger">Delete</button>
Script to send HTTP request from the button click, this code should go in the same file as your button above, or as an include JS file that the HTML page has imported:
<script>
var del_btn = document.getElementById("del-btn");
del_btn.addEventListener("click", function(e) {
var user = <%- JSON.stringify(user) %>;
var xhr = new XMLHttpRequest();
xhr.open("DELETE", "/user/" + user._id);
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
console.log(xhr.responseText);
window.location.href = "/users";
}
};
xhr.send();
//make XMLHttpRequest to delete the poll here
}, false);
</script>
in your server side route, note how the response is just a success code. It's the XMLHTTP Request from the client side that does the redirection:
app.delete('/user/:id', isLoggedIn, function(req,res){
User.remove({
_id: req.params.id,
ownerID: req.user._id
}, function (err, user) {
if (err)
return console.error(err);
console.log('User successfully removed from polls collection!');
res.status(200).send();
});
});