Redirect and render template with new variables - node.js

I will show my code first in order to be clear.
router.get("/add", (req, res)=>{
res.render("user/add.ejs");
});
router.put("/add/pi", (req, res)=>{
if(condition){
//do something
}else{
res.redirect("/user/add");
//res.render("user/add.ejs", {error: "At least one field should be filled in order to submit the form", type: "form error","location": "form-container"});
}
});
Ejs:
<% if(error){ %>
<small id="personalinformationError" class="form-text text-danger"><%= error %></small>
<% }%>
I want to be able to render the ejs template with the object in the render() in the comment. I tried to render it like in the comment without redirect() and it shows an error whenever I mention the variable name. The error goes like variable is not defined.
Thank you in advance.

Related

Not being able to delete an item from to-do list using Item.removeOne( ) or Item.findByIdAndRemove( ) methods of mongoose in NodeJS

I am making a to-do list using mongodb,node.js,express and EJS. The part where I am stuck is I am not being able to delete and item from the list and the database. The idea is that on clicking a checkbox, the item beside will be deleted. Here is a layout for the same,
[https://i.stack.imgur.com/83gMW.png][1]
I made the necessary changes in my EJS file to create a "/delete" route as given below :
<%for(var i=0;i<taskslist.length;i++){%>
<form action="/delete" method="POST">
<div class="item">
<input type="checkbox" name="checkitem" value="<%= taskslist[i]._id %> " onChange="this.form.submit()">
<p><%= taskslist[i].activity %> </p>
</div>
</form>
<%}%>
In my app.js folder, I also made the necessary changes by using findByIdAndRemove( ) method for mongoose :
app.post("/delete", function (req, res) {
const delitem = req.body.checkitem;
Item.findByIdAndRemove(delitem, function (err) {
if (err) {
console.log("Error");
} else {
console.log("Succesfully deleted" + delitem);
res.redirect("/");
}
});
console.log(delitem);
});
However, the item is not getting deleted from the database and an error is showing in terminal, even though the console.log(delitem) is working and returning the id of the item whose checkbox is selected.
I am also giving a screenshot of the output I am getting at the terminal:
[https://i.stack.imgur.com/hGEkn.png][1]
All the methods related to adding items and creating database are working. I don't understand where the error is. Please help me out with this.

Express JS does not perform delete

PUGJS script
form(id="form1" action="/delete" method="POST")
input(type="submit",name=+item['id'] value="delete")
My ExpressJS code
router.post('/delete', function(req, res, next) {
var id = req.params("i");
console.log("i am 0")
MongoClient.connect(url, function(err, db) {
console.log("i am 1")
db.collection('books', function(err, book) {
db.collection.deleteOne( {_id: new mongodb.ObjectID(id)} );
console.log("i am 2")
if (err) {
throw err;
} else {
db.close();
res.redirect('/');
}
});
});
});
Trying to perform a delete request but it does not even print ("i am 0")
can not determine what's broken with the code
NPM response POST /delete 404 7.247 ms - 1202
When you see a 404 the root cause is definitely how you set up the routing. This code would be successfully called if it is in app.js/server.js (or whatever your root express file is), but a 404 means that you have placed it in a secondary file and are using another path in there somewhere.
With that said, you also have an issue with how your route is defined if you want to read a route parameter (which is what the first line of your route handler tries to do).
router.post('/delete/:i', function...
The form itself isn't passing any id though through name (or id). You could either pass the id through the url called:
action= "/delete?id=" + id
...and read this in your route handler using req.query.id or you could insert a hidden input in the form and read it using req.body.id.
Also, the form name attribute has been deprecated and should be replaced with id.
Then, it's important to note that pug is highly dependent on indentation. Your code as pasted will generate an empty form and a separate input field.
This:
form(id="form1" action="/delete" method="POST")
input(type="submit",name=+item['id'] value="delete")
Generates this HTML:
<form id="form1" action="/delete" method="POST"></form>
<input type="submit" name="itemId" value="delete">
If you change the pug template to this (note the two additional spaces on the input line):
form(id="form1" action="/delete" method="POST")
input(type="submit",name=+item['id'] value="delete")
You will get this, which should work as expected:
<form id="form1" action="/delete" method="POST">
<input type="submit" name="itemId" value="delete">
</form>
Then, there's the problem in your delete function where you're missing a callback.
db.collection.deleteOne( {_id: new mongodb.ObjectID(id)} );
You need to either add a promise or callback here otherwise your code will move straight to close the connection.

express-validator error message attributes and location

I am using expressJS, Node and Handlebars.
In my post function I have the following:
routes.js
req.assert("referenceNumber", "Enter ...").notEmpty();
req.assert("yourPostcode", "Enter ...").notEmpty();
var errors = req.validationErrors(true);
if (errors) {
res.render('<page>/index', {
title: "<title>",
errors: errors
});
} else {
// Redirection
}
index.hbs
{{#if errors}}
<ul>
{{#each errors}}
<li>{{this.msg}}</li>
{{/each}}
</ul>
{{/if}}
This outputs a list of errors on submission which is great. The problem is I need the error message located next to the form field as well as.
So ideally I can target each error by name e.g. "referenceNumber", "yourPostcode".
I have thought about maybe having a variable inside the routes.js like so:
if (errors) {
res.render('<page>/index', {
title: "<title>",
referenceNumber: <something>,
yourPostcode: <something>
});
And perhaps be able to do something funky this way.
It would also be very good associating an id with each error message to act as an anchor link to each error form field.
Totally stumped with this one, and would really appreciate some help.

Unable to display flash message in view with ejs template

I am a newbie in NodeJS. I have a problem that I am unable to show flash message in my view.
Here is my Controller,
index : function(req, res){
res.locals.flash = _.clone(req.session.flash);
res.locals.layout = false;
res.view('login');
},
login : function(req, res){
....
if(!admin){
req.session.flash = {
err : 'User is not found.' // My flash message
}
res.locals.layout = false;
res.redirect('login');
return;
}
.....
}
Here is my view,
<% if(flash && flash.err) { %>
<div class="alert alert-danger">
<% JSON.stringify(flash.err) %>
</div>
<% } %>
When login is false, it show only an empty alert box.
And I have a second problem. When I refresh page, The alert box isn't disappeared.
Could someone help me please.
Thanks a lot.
The alert box keeps on appearing because the req.session.flash object persists the session, so you need to null that out once it's used, or you can just simply use req.flash(), which does that for you. So change your index method to something like this:
index: function(req, res) {
// req.flash() returns the contents of req.session.flash and flushes it
// so it doesn't appear on next page load. No need to clone.
res.locals.flash = req.flash();
res.locals.layout = false;
res.view('login');
},
Now, onto the second problem. The error messages aren't appearing because you aren't using the proper EJS syntax to output escaped values into the view. All you need to do is change your code to this:
<% if(flash && flash.err) { %>
<div class="alert alert-danger">
// Change <% to <%=
<%= flash.err %>
</div>
<% } %>
No need to JSON.stringify, unless you like the quotes. Notice that I changed the <% to <%=, which in EJS means "escape this and output it". It's not template HTML or anything like that, so it's okay to escape it anyway.

"has no method 'forEach' TypeError" on Node.js-Ejs-Mongojs stack

I have this code on app.js that's a callback where all the content of the "locale" collection is found:
tester = function(callback) {
db.locale.find({}, function(err, locale) {
callback( null, locale )
});
};
This sets the "title" variable when "index" (the homepage) is accessed and pass the "locale" collection content to the variable "content" "stringifying" it beforehand (if I don't, I get [object],[Object]):
app.get('/', function(req, res) {
tester(function(err, locale) {
res.render('index', {title: "This is a test server", content: JSON.stringify(locale)});
});
});
And this forEach in the view "index.ejs" which should only return the "title" collections field as a result:
<ul>
<% content.forEach( function( item ){ %>
<li><%= item.title %></li>
<% }); %>
</ul>
Anyway the problem is that I get a "'TypeError' has no method 'forEach'" when I browse the page.. What could cause this behavior? Thank you!
You're stringifying the locale object before rendering it. Strings have no forEach method, only arrays! So long as you don't actually plan on printing the whole content object to the page, and assuming that locale is a Javascript object, you can skip the stringify part entirely, and just do:
res.render('index', {title: "This is a test server", content: locale});

Resources