Sending a DELETE request with EJS using Mongoose - javascript

So I have already made a Restful API with node and everything works but I am trying to add EJS to it so I can use HTML&CSS, I implemented GET and POST just fine but I am tripping up on DELETE.
Here is my code in my router to delete
listRouter.delete('/:id',
function(req, res) {
req.list = list;
req.list.remove(function(err){
if (err)
res.status(500).send(err);
else
res.redirect('/')
});
});
and here's my EJS for deletion
<form method="DELETE" action="/:id">
<button type="submit">Delete</button>
</form>
and this is the error I receive when I press the button
{
message: "Cast to ObjectId failed for value ":id" at path "_id"",
name: "CastError",
kind: "ObjectId",
value: ":id",
path: "_id"
}
The thing is though the same exact code works if it's modified for JSON so I don't know if its EJS or my Javascript.
Thanks

i think html5 just support post and get in method form attribute
however, in my case if i don't using form for submit, here example
example in html or front end
<a class="btn btn-raised btn-danger" href="/admin/dashboard/detele/<%= data.userId %>">Delete</a></td>
<!-- The href needs to point at a link where data.userId is shown. Hence you need the = after <% for ejs to show the variable. -->
In app.js for the url delete
app.get('/admin/dashboard/detele/:id', users.deleteUser);
in express users.js
exports.deleteUser = function(req, res) {
users.findOneAndRemove({
userId: req.params.id
}, function(err, user) {
if (err) throw err;
console.log("Success");
});
res.redirect('/admin/dashboard');
}
don't forget creating mongo model for mongoose
var skema = new mongo.Schema({
name: String,
email: String,
password: String,
date: {
type: Date,
default: Date.now
},
admin: Boolean
});
var users = mongo.model('accounts', skema);
i using EJS here, hope it's help you
more helpful link1
more helpful link2

giving up use of method-override can be solution
I used different url to solve this.
<form action="/quake/forum/update/<%= post._id %>?_method=put" method="post">
and
<form action="/quake/forum/delete/<%= post._id %>?_method=delete" method="post" class="d-inline">
and router
main router
app.use('/quake/forum',forumRouter); //this is for just making sure explaination clear
sub router (forumRouter)
router.post('/delete/:id', function (req, res) {
and
router.post('/update/:id', function (req, res) {

Related

My req.body object is showing as empty when I submit a PUT request. I am using the method override middlware

I am trying to update a form using the put method. I am using method override middleware to make my form use a PUT request instead of a POST. when I console log the req.body to see if any information is coming through its empty.
Here is my ejs code:
<form action="/edit/<%= topic._id %>" method="post" class="formCard card">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="Make Edit" class="btn btn-dark">
</form>
I removed the input data since its not necassary.
Here is my express PUT method:
router.put('/edit/:id', async (req, res) => {
let topic = await Topic.findById(req.params.id)
topic = await Topic.findOneAndUpdate({_id: req.params.id}, req.body, {
new: true,
runValidators: true
})
console.log(req.body)
})
I am also using :
app.use(express.urlencoded({extended: true}))
app.use(express.json())
why am I not able to perform a update? Im confused on why the req.body is empty and not the updated fields in my form when I click the submit button?
I actually forgot to add the "name" attribute to my inputs! I can't believe I forgot that. When working with a form when the request gets sent it grabs those name fields. That's why the payload was empty.
router.put('/edit/:id', (req, res) => {
Topic.findByIdAndUpdate({_id: req.params.id}, req.body).then( function() {
Topic.findOne({_id: req.params.id}).then(topics => {
res.send(topics);
});
});
});
Did you try this way?

DELETE Request with nodejs and Mongoose

I'm struggling to delete a row from a collection of my database using mongoose. The console said that deleting was successful (as I handled error), but when I check my database, the row is still here. I successfully add a member with a post request, but I was not able to delete it.
I suspect my route file or my hbs file.
Here is the code :
Index.js (the route part)
app.get('/delete',(req,res) => res.render('delete', {
title:'Member App',
}));
routes/members.js
// Delete member : DELETE
router.get("/delete", (req,res)=>{
console.log(req.params.id);
Member.deleteOne({ _id: req.params.id }, function(err,data) {
if (!err) {
console.log(data);
console.log("member successfully deleted")
}
else {
console.log("error")
}
});
res.redirect("/");
});
delete.hbs
<h1 class = "text-center mb-3">{{title}}</h1>
<form action="/delete" method ="DELETE" class="mb-4">
<div class="form-group">
<label for="Id">Id</label>
<input type="Id" name="Id" class ="form-control">
</div>
<input type="submit" value ="Delete member" class="btn">
</form>
The console : (it seems that the data from my callback is undefined)
Connected to mongoDB
undefined
{ n: 0, ok: 1, deletedCount: 0 }
member successfully deleted
Your input type tag is wrong.
<input type="Id" name="Id" class ="form-control">
There is no "Id" type in input (see input types values)
You don't use correct field
req.params.id
Is used, but I don't see any params in your request.
You only have the body filled with Id so in order to use it, you should call :
req.body.Id
First of all the absence of an error does not guarantee the deletion of a record in the database. So in this case prefer to use findOneAndRemove method.
Second res.redirect("/"); will called before record removing has done, so redirect should be moved into callback function like:
Member.findOneAndRemove({ _id: req.params.id }, function(err, member) {
if (!err && member) {
console.log(member);
console.log("member successfully deleted")
}
else {
console.log("error")
}
res.redirect("/");
});

Express/Mongoose is only saving partial request data to database

I think this is related to how I've defined my schemas, but I can't seem to find where the bug is... I have an almost identical file set up that's working perfectly and I've unfortunately not been able to find a duplicate of this issue anywhere.
When sending an API request to my local Express instance via Postman, only the 'title' request body value is stored in the database. I am sending the following simple request to my route as Application/Json (thought the same happens when using x-www-form-urlencoded):
{
"postTitle": "title goes here",
"postContent": "body goes here",
"isPublished": true
}
This is clearly being registered in express, as if I log the object I can see this data (plus timestamps and an _id):
{ _id: 5b07d9c0b8124e0599079c04,
postTitle: 'title goes here',
postContent: 'body goes here',
isPublished: true,
createdAt: 2018-05-25T09:39:12.869Z,
updatedAt: 2018-05-25T09:39:12.869Z,
__v: 0 }
However, when I send a get request to my route on this object using its ID, I receive the following in response:
{ "_id": "5b07d9c0b8124e0599079c04" }
Likewise, if I send a request to list all objects, I receive the following response:
{
"posts": [
{
"_id": "5b07d9c0b8124e0599079c04"
},
{
"_id": "5b07d9c0b8124e0599079c03"
},
{
"_id": "5b07d9914f10ce058f137eba"
}
]
}
Weirdly, sometimes the post title sent as part of the response is included in the response, and sometimes it isn't.
My schema is as follows:
var postSchema = new Schema({
postTitle: String,
postContent: String,
isPublished: Boolean
},
{
timestamps: true
});
My post API route for POST requests is as follows:
router.post('/posts', (req, res, next) => {
var postTitle = req.body.postTitle;
var postContent = req.body.postContent;
var isPublished = req.body.isPublished;
var newPost = new Post({
postTitle: postTitle,
postContent: postContent,
isPublished: isPublished
});
newPost.save(function (error) {
if (error) {
console.log(error)
}
res.send({
success: true,
message: 'Post saved successfully!'
})
})
});
(If you're not using Router, you'll have 'app.post' instead of 'router.post') Again, this is a bit longwinded but everything works fine.
My GET route is as follows:
router.get('/posts', (req, res) => {
Post.find({}, 'title content published', function (error, posts) {
if (error) { console.error(error); }
res.send({
posts: posts
})
}).sort({_id:-1})
});
OK - so, by going through my code in detail I've figured out where I was going wrong and fixed the issue, however, in my searching I found very little in the way of results. I'm pretty new to Express, so I'm going to outline the cause of the issue and how I resolved it in order to potentially save someone else a bunch of time if they make the same stupid mistake.
Now, the issue I'm having results from the way I was retrieving the data and serving that in response to get requests. As an example, here's my GET route to list all of the objects.
I was entirely focusing on the post request and assuming it was a problem with the database. It turns out what I'd actually done, is in order to make my schemas and routes less confusing, I'd changed the names of the relevant variables. What I'd forgotten to do, however, is update this line in my GET route to reflect the change:
Post.find({}, 'postTitle postContent isPublished', function (error, posts) {
Which I'd left as:
Post.find({}, 'title content published', function (error, posts) {
The reason the title sometimes displayed is that I tried undoing changes back and forth to spot the issue.
I know this is a super basic query but I got stuck on this for the best part of a day, and the only other relevant discussion on this ended with OP saying that it magically fixed itself.

findByIdAndRemove resulting in an Error

Can anyone please help spot why the mongoose findByIdAndRemove in the delete route below...
//DELETE Route
app.delete("/blogs/:id", function(req, res){
//Destroy blog
Blog.findByIdAndRemove(req.params.id, function(err){
if(err){
res.send(err);
} else {
res.redirect("/blogs");
}
});
});
...generates the error below:
message: "Cast to ObjectId failed for value "5a6a8f967c9a190507b03433 " at path "_id" for model "Blog"",
name: "CastError",
stringValue: ""5a6a8f967c9a190507b03433 "",
kind: "ObjectId",
value: "5a6a8f967c9a190507b03433 ",
path: "_id"
Many thanks in anticipation of your help.
The problem is that you're sending a 16 character long String from the client while the method findOneByIdAndRemove demands an ObjectId. Doing this will eradicate the issue,
var mongoose = require('mongoose'); //remove it as you might already it
var ObjectId = mongoose.Types.ObjectId;
app.delete("/blogs/:id", function(req, res){
//Destroy blog
Blog.findByIdAndRemove(ObjectId(req.params.id), function(err){
if(err){
res.send(err);
} else {
res.redirect("/blogs");
}
});
});
Also, make sure that the _id is 16 character long, no spaces on either side is allowed.
Many thanks #vicbyte and Nilesh Singh for your contributions.
Indeed the code was failing due to the space at the end of the id: "5a6a8f967c9a190507b03433 ". The space came from the form issuing the DELETE:
<form id="delete" action="/blogs/<%= blog.id %> ?_method=DELETE" Method ="POST">
<button class = "ui red basic button">Delete</button>
</form>
Revising the the form as below...
<form id="delete" action="/blogs/<%= blog.id %>?_method=DELETE" Method ="POST">
<button class = "ui red basic button">Delete</button>
</form>
...cleared the error.
use async await. For Example:
async function(req,res) {
await Blog.findByIdAndRemove();
}

Unable to render data in my view for my express app

I am attempting to get data returned from a database rendered in my web page, but have been unable to do so. I am using using ejs as my templating engine, bookshelf(orm) and express as my node framework.
My model looks like this:
'use strict';
var bookshelf = require('../bookshelf');
var Contact = bookshelf.Model.extend({
tableName: 'contacts',
});
module.exports = Contact;
My controller looks like this:
function list(req, res, next) {
new Contact().fetchAll()
.then(function(contacts) {
var contacts = contacts.toJSON();
var contacts = JSON.stringify(contacts);
console.log(contacts)
res.render('contacts', {
contacts: contacts
});
}).catch(function(error) {
console.log(error);
res.send('An error occured');
})
}
And my template looks like this:
<% include partials/header %>
<h1><%= test %></h1>
<ul>
<% contacts.forEach(function(contacts){ %>
<li><%= contacts.firstName%></li>
<% }) %>
</ul>
<% include partials/footer %>
What I wish to happen is for that for each contact their first name shold be displayed on the page. However nothing is displayed even though the console.log statement (in the controller) displays this in the console:
[{"id":1,"firstName":"tom","lastName":"jones","emailAddress":"joney#test.com"},{"id":2,"firstName":"don","lastName":"jon","emailAddress":"don#test.com"}]
So data is returned from the DB, just not rendered in my view. Can anybody help me out with what I am doing wrong?
Method 2:
Below is a new way I have tried to do this. However this just results in the JSON been displayed on my web page.
function list(req, res) {
Contact.fetchAll()
.then(contacts => res.json({
contacts
})
).catch(function(error){
console.log(error);
res.send('An error occured');
})
}
It seems that bookshelf orm return a collection object, and you can use .toArray() method to transform it to an array and then pass it to your view without calling JSON.stringify, Try this:
function list(req, res, next) {
new Contact().fetchAll()
.then(function(contacts) {
res.render('contacts', {
contacts: contacts.toArray()
});
}).catch(function(error) {
console.log(error);
res.send('An error occured');
});
}
You seem to be double toJSON()-ing your contacts collection. There is no need to call toJSON() explicitly if you're going to call JSON.stringify() afterwards, since that method already calls .toJSON() on its own.
However, that's not the problem here. The real problem is that you're stringifying the collection, meaning it's a string when used on the template, so it's not possible to treat it like an object.
If you just remove the JSON.stringify(contacts); part it should work fine.

Categories