Cannot POST error using Express, Mongoose, EJS - node.js

(For the solution check the last answer)
I'm creating object with rating system with default value of 0. What I'm trying to do is to update the rating value by choosing one of the options in the <select> dropdown menu. The problem is when I'm submiting the selected value it sends the 'Cannot POST / ...' error.
Here's the app.js code with post and get requests:
// Updating Single Object
app.post('project/:projectId', (req, res) => {
const project = {};
project.rating = req.body.rating;
Project.update({_id: request.params.projectId}, project, (err) =>{
if(err){
console.log(err);
return;
} else {
res.redirect('/project/:projectId');
}
});
});
// Route To Single Project
app.get('/project/:projectId', (req, res) => {
const requestedProjectId = req.params.projectId;
Project.findOne({_id: requestedProjectId}).populate('image_file').exec((err, project) => {
res.render('project', {
project: project
});
});
});
And the form:
<form action="/project/<%= project.id %>" method="post">
<select class="" name="rating">
<option value="0">Rate us</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<input type="submit" value="Vote">
</form>
I think I'm missing something but can't figure it out.
Thank you in advance.

Just change your url in routes, use /project/:projectId instead of project/:projectId in app.post() method

Solved it after 3 hours, realizing I was missing the / before project in the url route.
app.post('project/:projectId', (req, res) => {

Maybe instead of:
<form action="/project/<%= project.id %>" method="post">
you should use:
<form action="/project/<%= project._id %>" method="post">

Related

How to load products based on category selection that the user selected using mongoose and nodejs

Here is the scenario: the client choosed category type then in the products selection i want to load only the products that belongs to this category
what i tried is to use one function to get all categories which will return all categories
and the other one is to get the productCategory based on the category selection that the user select it. but that gives me error in the ejs file that productCategory the variable that i passed in the second function is not defined.
the callback function
exports.makeABill = (req, res, next) => {
console.log('get Bill page');
categoryDB.find({}, function(err, data) {
res.render('bill/makeABill.ejs', { categories: data });
});
// categoryDB.findOne(req.body.categoryName, function(err, result) {
// res.render('bill/makeABill.ejs', { productCategory: result });
// });
}
the two input
<label for="categoryName"> Category : </label>
<select class="form-control form-control-sm" id="categoryName" autofocus>
<option value="">Select Category</option>
<% categories.forEach(function (category) {%>
<option> <%= category.categoryName %> </option>
<%})%>
</select>
<br>
<!--product-->
<label for="productsCategory"> Product Name : </label>
<select class="form-control form-control-sm" id="productsCategory" name="productsCategory" autofocus>
<option value="">Select Product</option>
<% productCategory.forEach(function (category) {%>
<option> <%= category.productsCategory %> </option>
<%})%>
</select>
<br>
Try this for filter {columName : values}
categoryDB.findOne({categoryName : req.body.categoryName}, function(err, result) {
res.render('bill/makeABill.ejs', { productCategory: result });
});

req.body option selected express ejs

Hi would like to send the selected option in dropdown menu, to show only the products from my mongodb.
If i use a submit button, works, but i would like to do without button. some help?
app.post('/windproducts', async (req, res) =>{
let tipoProducto = req.body.tipo_producto;
console.log(tipoProducto)
const windproducts = await WindProduct.find({"tipo_producto": {$eq:tipoProducto}})
res.redirect('windproducts/tablas', {windproducts})
}
)
in EJS:
<form action="/windproducts" method="POST">
<select id="productosTipo" class="validated-form" name="tipo_producto">
<option name="" value="">Todo</option>
<option name="tabla" value="tabla">Tabla</option>
<option name="vela" value="vela">Vela</option>
</select>
<!-- <button class="btn btn-success">mostrar</button> -->
</form>
Thanks
<% %>
use this syntax in your view file to use foreach loop on object
<%
Object.keys(obj).forEach(function(key) {
%>
// HTML Code
<%
});
%>

Standardize Dropdown's Selected Handlebars Helper

I'm facing the following challenge building some dropdowns with Handlebars.
Instead of modeling the dropdown's select this way:
<div class="form-floating col-3">
<select name="sport" class="form-select" id="floatingSelect">
<option {{selectedSport sport 'all'}} value="all">All</option>
<option {{selectedSport sport 'Hiking'}} value="Hiking">Hiking</option>
<option {{selectedSport sport 'Mountaineering'}} value="Mountaineering">Mountaineering</option>
<option {{selectedSport sport 'Climbing'}} value="Climbing">Climbing</option>
<option {{selectedSport sport 'Mountain biking'}} value="Mountain biking">Mountain biking</option>
</select>
<label for="floatingSelect">Sport</label>
</div>
<div class="form-floating col-2">
<select name="difficulty" class="form-select" id="floatingSelect">
<option {{selectedDifficulty difficulty 'all'}} value="all">All</option>
<option {{selectedDifficulty difficulty 'Easy'}} value="Easy">Easy</option>
<option {{selectedDifficulty difficulty 'Medium'}} value="Medium">Medium</option>
<option {{selectedDifficulty difficulty 'Hard'}} value="Hard">Hard</option>
<option {{selectedDifficulty difficulty 'Expert'}} value="Expert">Expert</option>
</select>
<label for="floatingSelect">Difficulty</label>
</div>
I would like to use the same helper for both of them, but I still don't know how to do it. (btw, ignore the fact that I should be using an {{#each}} for displaying the options :P)
The controller:
module.exports.list = (req, res, next) => {
const filters = req.query;
const { location, sport, difficulty } = req.query;
const criterial = Object.keys(filters)
.filter((key => filters[key] !== 'all'))
.reduce((criterial, filter) => {
if (filters[filter]) criterial[filter] = filters[filter];
return criterial;
}, {});
Route.find(criterial)
.then(routes => {
res.render('routes/list', { routes, location, sport, difficulty })
})
.catch(next)
}
The helpers:
hbs.registerHelper('selectedSport', (option, sportValue) => {
return option === sportValue ? ' selected' : '';
})
hbs.registerHelper('selectedDifficulty', (option, difficultyValue) => {
return option === difficultyValue ? ' selected' : '';
})
Many thanks for your help! :)
Finally I solved it this way:
Instead of typing all the options directly on the HBS, I create these with a helper that renders each option.
<div class="form-floating col-3">
<select name="sport" class="form-select" id="floatingSelect">
{{#each sportOptions as |sportOption|}}
{{option ../sport sportOption}}
{{/each}}
</select>
<label for="floatingSelect">Sport</label>
</div>
<div class="form-floating col-2">
<select name="difficulty" class="form-select" id="floatingSelect">
{{#each difficultyOptions as |difficultyOption|}}
{{option ../difficulty difficultyOption}}
{{/each}}
</select>
<label for="floatingSelect">Difficulty</label>
</div>
The helper receives 2 parameters: sport and sportOption and according to their value, returns a string cointaining the option with the selected attribute or not.
hbs.registerHelper('option', function (selectedValue, value) {
const selectedProperty = value == selectedValue ? 'selected' : '';
return new hbs.SafeString(`<option value=${value} ${selectedProperty}>${value}</option>`);
});
sportOption and difficultyOption are arrays with all the possibilities inside them.
I hope that, if someone else has the same problem, this can be of any help :)

Getting undefined at node when i am selecting it by req.body.status

here is my code for select in html
<select class="status" name="status">
<option value="Pending">Pending</option>
<option value="Done">Done</option>
</select>
here is my code for server.js
App.post('/userAddedIntoTable',(req,res)=>{
console.log(req.body.status);
res.send("testing");
});

How to pass function as variable in Express-handlebars

I am trying to pass a function as a variable and call that function using onclick=""
but the function is executing before passing.
Here is the code.
seminar.js
function getco(){
console.log('hello');
}
router.get('/add',(req,res)=>{
res.render('cms/seminar/add',{
getco:getco()
});
});
add.handlebars
<form action="/cms/seminar/add" method="post">
<div class="form-group">
<label for="sel1">Game Name of the Seminar</label>
<select class="form-control" id="seminar_gamename" name="seminar_gamename" required onclick="getco">
<option value="pubg">Pubg</option>
<option value="candy_crush">Candy Crush</option>
<option value="fortnite">Fortnite</option>
<option value="mortal_combat">Mortal Combat 11</option>
<option value="far_cry_city">Far Cry City Dowm</option>
<option value="fortnite">Fortnite</option>
<option value="prince_of_persia">Prince of Persia:The Forgotten Sand</option>
</select>
</div>
</form>
//But the result im getting is 'hello' without even clicking
As mentioned in the comment above you are directly calling the function instead of passing it to frontend.
Try removing () from getco
`function getco(){
console.log('hello');
}
router.get('/add',(req,res)=>{
res.render('cms/seminar/add',{
getco:getco
});
});`
This allows you to pass the method as a variable and then in frontend use,
onclick="getco()"

Resources