I'm new to Express and databases. I'm trying to create a simple CRUD todo list by following several tutorials using Mongo DB (not Mongoose), Express, Node, and Handlebars.
I can create items from an input form and have them successfully save to the Mongo database and the page. I can't figure out how to delete each item based on a button click both on the page and from the database. Ideally, I want to target them based on the _id that Mongo creates.
I think the issue might be having something to do with the way I'm trying to select each item. Any suggestions or easier ways to implement this would be great!
Here is my code for Express:
// Connecting Mongo DB
MongoClient.connect(url, (err, client) => {
if (err) return console.log(err)
db = client.db('todoitems')
})
// Save items to DB from form
app.post('/items', (req, res) => {
db.collection('items').save(req.body, (err, result) => {
if (err) return console.log(err)
console.log(req.body, {_id: req.body._id})
res.redirect('/')
})
})
// Delete item on click from DB
app.delete('/items/:id', (req, res) => {
db.collection('items').remove({_id: req.body.id}, (err, result) => {
if (err) return console.log(err)
console.log(req.body)
res.redirect('/')
})
})
// Get items from DB to page
app.get('/', (req, res) => {
db.collection('items').find().toArray((err, result) => {
if (err) return console.log(err)
res.render('index', {
layout: false,
items: result
});
})
})
And here is my code from the Handlebars file:
<form action="/items" method="POST">
<input type="text" placeholder="item" name="item">
<input type="hidden" id="date" name="date" value="CurrentDate">
</form>
<ul>
{{#each items}}
<li>
<span>{{item}} |</span>
<span>{{date}}</span>
<button id={{_id}}>x</button>
</li>
{{/each}}
</ul>
If you are removing by _id, you need to pass an ObjectID(id) not a "string" id, something like:
remove({_id: mongodb.ObjectID( req.params.id)} ...
So, your code should be like:
app.delete('/items/:id', (req, res) => {
db.collection('items').remove({_id: mongodb.ObjectID( req.params.id)}, (err, result) => {
if (err) return console.log(err)
console.log(req.body)
res.redirect('/')
})
})
Related
app.get('/index', function(req, res){
Activities.find({}, function(err, activity){
if(err){
console.log(err);
}else{
res.render('index', {activities:activity});
}
});
Upcoming.find({}, function(err, upcomingActivity){
if(err){
console.log(err);
}else{
res.render('index', {upcoming:upcomingActivity});
}
});
});
I just want to get data of multiple collections and then pass it to index.ejs file so that i can use these data there.
I know using res.render() multiple times won't work but i have tried many things like saving founded data to variable , creating an object of these etc. But nothing
worked.
In your get response you should render only once the index page passing the parameters all together.
app.get('/index', function(req, res){
Activities.find({}, function(err, activity){
if(err){
console.log(err);
}else{
Upcoming.find({}, function(err, upcomingActivity){
if(err){
console.log(err);
}else{
res.render('index', {activity:activity, upcoming:upcomingActivity,});
}
});
}
});
});
It will work this way, since you have only a few collections but other way to do so is passing it as a global object and then rendering it.
Use then to render asynchronously
app.get('/index', (req,res) => {
Activities.find().then(activity => {
Upcoming.find().then(upcomingActivity => {
res.render('index', {Activities: activity, Upcoming: upcomingActivity})
}).catch(err => console.log(err))
}).catch(err => console.log(err))
})
im working with mongoose and when i tried using query like .findByIdAndRemove()
it deleted the content but not remove the product from the database
it just turn it to Null
like
{"_id":"5d67502aaffb3729a0e24904","name":null,"image":null,"price":null,"desc":null,"__v":0}
Form
<form action='/product/<%=product._id%>' method="POST">
<button type="submit" class="btn btn-danger">Delete</button>
</form>
//Route
router.post('/product/:productId',productController.deleteProduct)
//controller
//delete product
exports.deleteProduct = (req, res, next)=>{
const prodId = req.params.productId
Product.findByIdAndRemove(prodId)
.then(() =>{
console.log('has been deleted')
res.redirect('/product')
})
.catch(err=>{console.log(err)})
}
Could please try below delete script.
It's removing by one document using id
Product.remove({_id : new mongoose.Types.ObjectId(prodId)}, (err, result) => {
if(err) console.log(err);
else console.log(result)
})
It's removing document by _id
Product.findByIdAndRemove(prodId, (err, result) => {
if(err) console.log(err);
else console.log(result)
})
It's removing by one document
Product.remove({name: 'yourName'}, (err, result) => {
if(err) console.log(err);
else console.log(result)
})
or another option
Product.deleteOne({ name: 'Eddard Stark' }, callback);
In router
router.delete('/product/:productId',productController.deleteProduct)
In the front end, you call delete API. If the interest you can learn MEARN Stack CRUD operation in GitHub link
this is my post request to save to mongdb database
router.post("/create", async (req, res) => {
const createJottings = new Jottings({
title: req.body.title,
jottings: req.body.jottings
});
try {
await createJottings.save();
res.json(createJottings);
} catch (err) {
res.json({ message: err });
}
});
it works fine on postman but now i am trying to render it using handlebars to the client. this is the form for the client side using handlebars
<div class="card card-body">
<h3>
Edit Jottings/Idea
</h3>
<form action="/jottings/create" method="get">
<div class="form-group">
<label for="title">
Title
</label>
<input type="text" name="title" class="form-control" required />
</div>
<div class="form-group">
<label for="title">
Jottings
</label>
<textarea name="Description" class="form-control" required></textarea>
</div>
<button type="submit" class="btn btn-primary">
Submit
</button>
</form>
</div>
the form actually loads but when i press submit it doesnt save to mongodb server
{{#each getJottings}}
<div class="card card-body mb-2">
<h4>
{{title}}
</h4>
<p>
{{jottings}}
</p>
<a href="/jottings/edit/{{id}}" class="btn btn-dark btn-block">
Edit
</a>
</div>
{{else}}
<p>
No Ideas and Jottings listed
</p>
{{/each}}
code that outlists saved data in the database if i create it using postman it works but with the form it doesnt.
overview of my jottings route
// Require Mongoose
const router = require("express").Router();
// Setup Models for Jotting
const Jottings = require("../models/jottings.model");
// Setting Endpoints For Routes
// Get All Jottings
router.get("/", async (req, res) => {
try {
const getJottings = await Jottings.find({}).sort({ date: "desc" });
res.render("jottings/index", {
getJottings: getJottings
});
} catch (err) {
res.json({ message: err });
}
});
// Getting routes to set form
router.get("/add", (req, res) => {
res.render("jottings/add");
});
// Get Specific Jottings
router.get("/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
await Jottings.findById(id, (err, jottings) => {
if (!id) {
res.json({ message: err });
} else {
res.json(jottings);
}
});
} catch (err) {
res.json({ message: err });
}
});
// Post to create New Jottings for form
router.post("/create", async (req, res) => {
const createJottings = new Jottings({
title: req.body.title,
jottings: req.body.jottings
});
try {
await createJottings.save();
res.json(createJottings);
} catch (err) {
res.json({ message: err });
}
});
router.get("/edit/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
const editJottings = await Jottings.findOne({ _id: id });
res.render("jottings/edit", {
editJottings: editJottings
});
} catch (err) {
res.json({ message: err });
}
});
// Patch to Edit Jottings for form
router.patch("/edit/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
const editJottings = await Jottings.updateOne(
{ _id: id },
{ $set: { jottings: req.body.jottings } }
);
res.render("jottings/edit", {
editJottings: editJottings
});
} catch (err) {
res.json({ message: err });
}
});
// Delete to delete Jottings for form
router.delete("/delete/:id", async (req, res) => {
try {
// Requesting for request paremeter given to ever document created in mongoDB
const id = req.params.id;
const deleteJottings = await Jottings.deleteOne({ _id: id });
res.json(deleteJottings);
} catch (err) {
res.json({ message: err });
}
});
// Exporting router
module.exports = router;
i would like the details to be saved to the database when i click the submit button and also redirect me to a list of my saved details.
You form uses method GET while you defined router.post to handle form submission.
I have a route like this and works fine:
// Dashboard route
router.get('/dashboard', ensureAuthenticated, (req, res) => {
Note.find({user: req.user.id})
.then(notes => {
res.render('index/dashboard', {
notes: notes
});
});
});
on the dashboard.handlebars I can loop the array with:
{{#if notes}}
...
{{#each notes}}
{{title}}
{{body}}
{{/each}}
{{/if}}
I also have this other route, almost identical, but is not passing the array to the template:
// Admin Route
router.get('/admin', ensureAdmin, (req, res) => {
User.find({})
.then(users => {
console.log("Users count is: " + users.length)
console.log(users)
res.render('index/admin'), {
users: users
};
});
});
On the console I get both console.log working, I get the number of users and the info. So the Find() is working but the array seems like is not passed to the template.
I suspect it can be because I have a global var:
res.locals.user = req.user || null;
to keep the info of the logger user. But I changed the variables names on the Find() function and with no luck.
on the template I allways have "No users found" as result
{{#if users}}
<p>There are users</p>
{{else}}
<p>No users found</p>
{{/if}}
Any idea?
Solved, it was a ")" on bad place...
'index/admin')
was the cause
Solution is:
// Admin Route
router.get('/admin', ensureAdmin, (req, res) => {
User.find({})
.then(users => {
console.log("Users count is: " + users.length)
console.log(users)
res.render('index/admin', {
users: users
});
});
});
I want to integrate a button on my website that will open a port, recieve some data, update a database and then render the home page. Basically I need that botton to execute the code between the app.post's curly brackets.
That works fine when I click the button for first time but then, after rendering, I have to restart the server to do that again.
app.post('/test', isLoggedIn, (req, res) => {
port.on('data', function (data) {
sirDeAfisat+=data.toString('ascii');
if(checker.sfarsitSir(data)==true) {
if(checker.sirOk(sirDeAfisat)==true){
fs.appendFile("./log/date.txt",sirDeAfisat,(err)=>{
if(err) console.log(err.message);
});
const child=fork('./parser_ok.js');
child.send(`${sirDeAfisat}`);
child.on('message',(answ)=>{
console.log(`Sunt portul, am primit de la parser : ${answ}`)
child.kill('SIGINT');
});
}else{
fs.appendFile('./log/erori.txt',new Date().toISOString(),function (err){
if(err) console.log(err.message);
});
fs.appendFile('./log/erori.txt',"SIR !OK",sirDeAfisat,(err)=>{
if(err) console.log(err.message);
});
}
sirDeAfisat='';
port.close();
res.send(201);
return;
}
});
port.on('readable',() =>{
port.read();
});
});
isLoggedIn:
function isLoggedIn (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/');
}
and this is test.ejs
<!-- form -->
<form action="/test" method="post">
<input type="submit" class="btn btn-dark btn-lg">
</form>