how can I activate the edit button? mongodb - javascript

I got this error
CastError: Cast to ObjectId failed for value "details5f9c3b069dc8723528c64cc8" at path "_id" for model "Book"
the edit and delete button are not activated.
Help me to figure it out please. this is /routes/books.js
and what else do I upload here?
// GET edit an existing Book
router.get('/:id', (req, res, next) => {
let id = req.params.id;
book.findById(id, (err, bookToEdit) => {
if(err) {
console.log(err);
//res.end(err);
} else {
//show the edit view
res.render('books/details', {title: 'Edit Book', books: bookToEdit})
}
});
});
// POST and update the document
router.post('/:id', (req, res, next) => {
let id = req.params.id
let updatedBook = book({
_id: id,
title: req.body.title,
description: req.body.description,
price: req.body.price,
author: req.body.author,
genre: req.body.genre
});
book.updateOne({_id: id}, updatedBook, (err) => {
if(err) {
console.log(err);
res.end(err);
} else {
// refresh
res.redirect('/books');
}
});
});
// GET - process the delete by user id
router.get('/delete/:id', (req, res, next) => {
let id = req.params.id;
book.remove({_id: id}, (err) => {
if(err) {
console.log(err);
res.end(err);
} else {
// refresh
res.redirect('/books');
}
});
});
This is /books/details.ejs
<div class="container">
<div class="row">
<form class="form" method="post">
<div class="form-group">
<label for="TitleTextField">Title</label>
<input type="text" class="form-control" id="TitleTextField"
placeholder="Book Title" name="title" value="<%= books.Title %>" required>
</div>
<div class="form-group">
<label for="AuthorTextField">Author</label>
<input type="text" class="form-control" id="AuthorTextField"
placeholder="Book Author" name="author" value="<%= books.Author %>" required>
</div>
<div class="form-group">
<label for="PriceTextField">Price</label>
<input type="text" class="form-control" id="PriceTextField"
placeholder="Book Price" name="price" value="<%= books.Price %>" required>
</div>
</div>
</div>
and this is /books/indexejs
<% include ../partials/header.ejs %>
<!-- MAIN CONTENT -->
<div class="container">
<div class="row">
<!--Add-->
<i class="fa fa-plus"></i> Add a book
<br>
<br>
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th>Title</th>
<th class="text-center">Author</th>
<th class ="col-4">Price</th>
<th class="text-center">EDIT</th>
<th class="text-center">DELETE</th>
</tr>
</thead>
<tbody>
<% for (let count = 0; count < books.length; count++) { %>
<tr>
<td><%= books[count].Title %></td>
<td class="text-center"><%= books[count].Author %></td>
<td class="text-center">$<%= books[count].Price %></td>
<!--EDIT-->
</td>
<td class="text-center">
<a href="/books/edit<%= books[count].id %>" class="btn btn-primary btn-sm">
<i class="fas fa-pencil-alt"></i> Edit</a>
</td>
<!--DELETE-->
<td class="text-center">
<a href="/books/delete<%= books[count].id %>" class="btn btn-danger btn-sm">
<i class="fas fa-trash-alt"></i> Delete</a></td>
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
</div>
</div>
<% include ../partials/footer.ejs %>
this is /models/books.js
let mongoose = require('mongoose');
let Book = mongoose.Schema({
Title: String,
Description: String,
Price: Number,
Author: String,
Genre: String
},
{
collection: "books"
});
module.exports = mongoose.model('Book', Book);
hope these are helpful to fix the problems

You have an error that said that book.find and book.delete need an ObjectId as parameter. And details5f9c3b069dc8723528c64cc8 is not a valid ObjectId for Mongo.
Just read the error message !
Edition
Maybe you face this problem because you made a little mistake with resources, using same http POST to create and edit, giving the :id in path in both case.
If you have a POST / (no id in path) method to create books, letting mongodb generate ids, and have a PATCH (or PUT) /:id method to update those books, you probably will not have this kind of error anymore.
It will maybe sounds like stupid duplication but as your app will grow, you certainly will need to add some specific security rules.
Also, if I remember mongoose correctly, you're not supposed update the _id in second parameter for updateOne.
//no _id present in updatedBook
book.updateOne({_id: id}, updatedBook, (err) => { };

The default key of a document in MongoDB is _id who set an ObjectId in it.
ObjectId is a unique key who contained from some meaningful base on date and time (you can convert objectId to date).
You can read more about it here.
And your problem, it's really easy. You concat your ObjectId with details as you can see in the error.
details5f9c3b069dc8723528c64cc8 => 5f9c3b069dc8723528c64cc8

Related

cannot read properties of undefined(reading"name")

I trying to make a survey website and I have been stuck on this bug for hours. I have a from that has 5 inputs and it takes name, question and 4 options as text and submits them. when clicking on submit button the server recieves a post method with the action /all after getting /all the server should render all.ejs. below is my index.js file:
router.post('/all', function (req, res) {
const newsurvey=new survey({
"name":req.body.name,
"question":req.body.question,
"option1":req.body.option1,
"option2": req.body.option2,
"option3":req.body.option3,
"option4": req.body.option4,
})
survey.create(newsurvey)
console.log(newsurvey)
console.log(req.body.name)
res.render('all', { title: 'All Surveys', survey});
});
// initializing a new survey object
router.get('/addsurvey', function (req, res, next) {
survey.find((err, list)=>{
const newsurvey = new survey({
"name":"",
"question":"",
"option1":"",
"option2":"",
"option3":"",
"option4":""
}
)}
,res.render('surdetails', { title: 'Details', survey})
);
});
router.get('/all', function (req, res) {
survey.find((err, list)=>{
if (err){
return console.error(err);
}else{
res.render('all', { title: 'All Surveys', survey: survey });
}
})
});
and below is my all.ejs file which returns cannot read properties of undefined(reading"name"):
<tbody>
<!-- Template Row -->
<% for (let count = 0; count < survey.length; count++) { %>
<tr>
<td><%= survey[count].name %></td>
<td class="text-center"><%= survey[count].name %></td>
<td class="text-center"><%= survey[count].question %></td>
<td class="text-center">
<input type="radio" id="option1" name="option1" value="<%= survey[count].option1 %>">
<label for="option1"><%= survey[count].option1 %></label><br>
<input type="radio" id="option2" name="option2" value="<%= survey[count].option2 %>">
<label for="option2"><%= survey[count].option2 %></label><br>
<input type="radio" id="option3" name="option3" value="<%= survey[count].option3 %>">
<label for="option3"><%= survey[count].option3 %></label><br><br>
</td>
<td class="text-center">
<i class="fa fa-trash-o"></i> Delete
</td>
</tr>
<% } %>
</tbody>

Express-validator throwing error with valid fields

I'm relatively new to node and express, and have come across a problem I can't seem to solve.
So I came across with the problem trying to validate a create product form, that when I introduce correct values into the fields express-validator throws error.
This is my routes code:
router.post('/create', [
check('name').isLength({ min: 5 }).withMessage("Invalid Value"),
check('description').isLength({ min: 20 }).withMessage("Invalid Value")
] , upload.any() , productosController.guardarCreado);
This is my productosController code:
guardarCreado: (req, res, next) => {
let errors = validationResult(req);
if(errors.isEmpty()){
db.Product.create({
name: req.body.nombre,
description: req.body.descripcion,
size: req.body.talle,
price: req.body.precio,
category_id: 2,
img_url: req.files[0].filename
})
res.redirect('/productos');
}else{
db.Category.findAll()
.then(function(categorias){
return res.render('crearProductos', { categorias: categorias, errors: errors.errors });
})
}
}
And my form code is from Bootstrap and the names of the form fields are the same as the names on the 'check' from my routes code:
<div class="col-md-3 mb-3">
<label for="validationDefault03">Nombre del Producto</label>
<input name="name" id="nombre" type="text" class="form-control" placeholder="Ej: Remera River Plate" >
</div>
<div class="col-12">
<label for="description" class="form-label">DescipciĆ³n:</label><br>
<textarea name="description" id="description" class="form-input"></textarea>
</div>
Error display on the the form via EJS:
<% if (typeof errors != 'undefined') { %>
<p style= "color: red">ERROR</p>
</div>
<ul>
<% for(let i = 0; i < errors.length; i++) { %>
<li>
<%= errors[i].msg %>
</li>
<% } %>
</ul>
<% } %>

Mongoose findByIdAndUpdate not working. {new: true} included

I tried to edit the info and update it, but the mongoose findByIdAndUpdate didn't work. The {new: true} is included, but it still shows the original one. In the database, the info is not updated either. The console shows PUT /blogs/:id 302.
The routes are as follows:
//edit
router.get('/blogs/:id/edit', function (req, res) {
Blog.findById(req.params.id, function (err, blogFound) {
if(err){
console.log(err);
}else{
res.render("edit", {blog: blogFound});
}
});
});
//update
router.put('/blogs/:id', function (req, res) {
Blog.findByIdAndUpdate(req.params.id, req.body.blog, {new: true},function (err, blogUpdated) {
if(err){
console.log(err);
} else{
res.redirect('/blogs/' + req.params.id);
}
});
});
The edit form looks like this:
<form class="ui form" action="/blogs/<%= blog._id %>?_method=PUT" method="POST">
<div class="field">
<label>Title</label>
<input type="text" name="title" value="<%= blog.title %>">
</div>
<div class="field">
<label>Image</label>
<input type="text" name="image" value="<%= blog.image %>">
</div>
<div class="field">
<label>Content</label>
<textarea name="description"><%= blog.description %></textarea>
</div>
<button class="ui primary button" type="submit">Submit</button>
</form>
it seems req.body.blog is undefined.
you have title, image and description in your body not grouped in blog object, so you shall write
const { title, image, description } = req.body;
Blog.findByIdAndUpdate(req.params.id, { title, image, description },
or smth like this

How to create self referencing MongoDB schema and post routes using nodejs?

I am trying to create parent-child like nested system where child has same schema as of parent.Below is my parent schema, here children refers to the parentSchema again,
var mongoose = require("mongoose");
var parentSchema = new mongoose.Schema({
name: String,
children:[
{
ref: this
}
],
});
module.exports = mongoose.model("Parent", parentSchema);
Routes looks like this
app.get("/", function(req, res){
Parent.find({}).populate("children").exec(function(err, allParents){
if(err){
console.log(err);
}else{
res.render("index",{parents: allParents});
}
});
});
app.post("/", function(req,res){
var name = req.body.name;
var desc = req.body.desc;
var newParent = {name: name, description: desc}
Parent.create(newParent, function(err, newlyCreate){
if(err){
console.log(err);
}else{
res.redirect("/");
}
});
});
app.post("/:id", function(req, res){
Parent.findById(req.params.id, function(err, parent){
if(err){
console.log(err);
res.redirect("/");
}else{
parent.children.push(req.body.child);
parent.save();
console.log(parent.children);
res.redirect("/");
}
});
});
The problem is when I send data from form to post route it prints it but after pushing it into parent.children and then printing parent.children is shows null. Where is the problem???
EJS page looks like below:-
<form action="/" method="POST">
<div class="form-group">
<input type="text" name="name" placeholder="Name">
</div>
<div class="form-group">
<input type="text" name="desc" placeholder="Description">
</div>
<div class="form-group">
<button class=btn-primary btn-block">Submit</button>
Go Back
</div>
</form>
<div class="row">
<% parents.forEach(function(module){%>
<ul class="list-group">
<li class="list-group-item" style="margin-bottom: 5%;">
<h2><%= module.name%></h2>
<%= module.description %>
<% console.log(module.children) %>
<%module.children.forEach(function(node){%>
<% console.log(node) %>
<%});%>
<div class="container">
<div class="row">
<div>
<form action="/<%= module._id %>" method="POST">
<div class="form-group">
<input type="text" name="name" placeholder="Name">
</div>
<div class="form-group">
<input type="text" name="desc" placeholder="Description">
</div>
<button>Submit</button>
</form>
</div>
</div>
</div>
</li>
</ul>
</div>
<% }); %>
</div>
Can anyone tell where is the problem in above code or can anyone suggest any other way to make this type of parent-child structure????
It seems that parent.save() is asynchronus. Maybe you can try this instead.
parent.save().then(()=>{
console.log(parent.children);
res.redirect("/");
});
or you can use async-await after putting async before function definition,
await parent.save();
console.log(parent.children);
res.redirect("/");
Please do write in comment if problem still persists.

using hidden fields in express js

Im trying to pass value of a hidden id field and use it to retriev records from mongodb and display it on profile page,after clicking "read more" on index page.This the index.ejs:
<% for(i=0; i<users.length; i++){%>
<div class="col-lg-3 center">
<div class="text-center">
<img class="img img-circle" src="<%= users[i].image %>" height="120px" width="120px" alt=""> <br>
<h4><b><%= users[i].fname %> <%= users[i].lname %></b></h4>
<ul class="list-inline social-buttons">
<li><i class="fa fa-linkedin"></i></li>
<li><i class="fa fa-github"></i></li>
<li><i class="fa fa-twitter"></i></li>
</ul>
<input type="hidden" name="id" value="<%= users[i]._id %>" >
<p><%=users[i].bio %>....Read More</p>
</div>
</div><!-- col-lg-3 -->
<% } %>
and here is profile.ejs:
<div class="medium-4 small-12 columns">
<h3> <%= users.fname %> <%= users.lname %></h3>
<p>Username: <%= users.username %></p>
<p>Email: <%= users.email %></p>
<p> Software Developer at <%= users.role %></p>
</div>
and express routes ,users.js.
app.get('/prof',function(req, res) {
var id=req.body.id;
var user = new User();
mongoose.model('User').findById(id,function(err, users){
console.log(users);
res.render('pages/profile',{users:users});
});
});
This gives me an error "Cannot read property 'username' of null.."
What am I missing?
You are doing a GET operation yet you are trying to send the id value through the POST parameters which are grabbed using req.body.variable_name.
In this case you don't need a hidden field as that needs a POST operation to send to the server. Try sending the id as a URL parameter which can be grabbed using req.param.id or req.query.id, for example
http://example.com/api/users?id=4&token=sdfa3&geo=us
or
http://example.com/api/users/4/sdfa3/us
If you want to get a query parameter ?id=57ada56845b8466147fc35b0, then use req.query
URL:
// GET /prof?id=57ada56845b8466147fc35b0
Markup:
<p><%=users[i].bio %>....Read More</p>
Route:
app.get('/prof', function(req, res) {
var id = req.query.id; // 57ada56845b8466147fc35b0
mongoose.model('User').findById(id, function(err, user){
console.log(user);
res.render('pages/profile', { users: user });
});
});
For the other parameter usage
URL:
// GET /prof/57ada56845b8466147fc35b0
use req.params.id
Markup:
<p><%=users[i].bio %>....Read More</p>
Route:
app.get('/prof/:id', function(req, res) {
var id = req.params.id; //57ada56845b8466147fc35b0
mongoose.model('User').findById(id, function(err, user){
console.log(user);
res.render('pages/profile', { users: user });
});
});

Categories