Book List CRUD App with Mongoose - Delete & Update
Lesson Objectives
Deletion:
- Create a Delete Button
- Create a DELETE Route
- Have the Delete Button send a DELETE request to the server
- Make the DELETE Route Delete the data from MongoDB
Edit/Update:
- Create a link to the edit route
- Create an edit route
- Create an PUT route
- Have the edit page send a PUT request
- Make the PUT Route Update the data in MongoDB
- Make the PUT Route Redirect Back to the Index Page
Create a Delete Button
In your index.ejs file, update the li item which is created for each data entry to include a delete form:
<% books.forEach(book => { %>
<li>
<a href="/books/<%=book._id %>"> <%=book.title %> </a>
<form>
<input type="submit" value="DELETE" />
</form>
</li>
<% }) %>
Create a Delete Route
Remember INDUCES (index, new, delete, update, create, edit show) to help keep your routes organized and avoid conflicts.
In server.js:
app.delete("/books/:id", (req, res) => {
res.send("deleting...")
})
Have the Delete Button send a DELETE request to the server
When we click "DELETE" on our index page (index.ejs
), the form needs to make a DELETE request to our DELETE route.
The problem is that forms can't make DELETE requests. Only POST and GET. We can fake this, though. First we need to install an npm package called method-override
npm install method-override
Now, in our server.js file, add:
// Dependencies
const methodOverride = require("method-override")
// Middleware
app.use(methodOverride("_method"))
Now go back and set up our delete form to send a DELETE request to the appropriate route. We're just updating the opening form tag.
<form action="/books/<%= book.id %>?_method=DELETE" method="POST">
<input type="submit" value="DELETE" />
</form>
STOP! Check your work. You should be able to visit one of your show pages to grab an ID that you know exists.
Next, try clicking one of the delete buttons and make sure you're getting the expected output of 'deleting...' sent in the browser.
Make the Delete Route Delete the Document from MongoDB
Also, have it redirect back to the books index page when deletion is complete
In server.js
:
// Delete
app.delete("/books/:id", (req, res) => {
Book.findByIdAndRemove(req.params.id, (err, data) => {
res.redirect("/books")
})
})
Hint: Deleted all your data? Remember you can hit your seed route http://localhost:3000/books/seed
to re-populate your database! Isn't that so much easier than adding everything in manually from a form?
Create a link to an edit route
In index.ejs
:
<% books.forEach(book => { %>
<li>
<a href="/books/<%= book._id %>"> <%=book.title %> </a>
<form action="/books/<%=book.id %>?_method=DELETE" method="POST">
<input type="submit" value="DELETE" />
</form>
<a href="/books/<%=book._id %>/edit">Edit</a>
</li>
<% }) %>
STOP! Check your work. We don't have an edit view, but the link should be working.
Create an Edit Route
Remember INDUCES!
In server.js
:
// Edit
app.get("/books/:id/edit", (req, res) => {
Book.findById(req.params.id, (error, foundBook) => {
res.render("edit.ejs", {
book: foundBook,
})
})
})
Create an Edit Page
Create an edit.ejs
file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Book List</title>
</head>
<body>
<h1>Edit Book</h1>
<form>
<!-- NOTE: the form is pre-populated with values for the server-->
Title: <input type="text" name="title" value="<%=book.title%>" /><br />
Author: <input type="text" name="author" value="<%=book.author%>" /><br />
Completed: <input type="checkbox" name="completed" <% if(book.completed
=== true){ %> checked <% } %> />
<br />
<input type="submit" value="Submit Changes" />
</form>
</body>
</html>
STOP! Check your work. Make sure the edit page is rendering properly.
Create an Update Route (PUT)
Remember INDUCES!
In server.js
:
// Update
app.put("/books/:id", (req, res) => {
if (req.body.completed === "on") {
req.body.completed = true
} else {
req.body.completed = false
}
res.send(req.body)
})
Have the edit page send a PUT request
In edit.ejs
:
<form action="/books/<%=book._id%>?_method=PUT" method="POST"></form>
Make the PUT Route Update the Document in MongoDB and Redirect back to the Show Page
// Update
app.put("/books/:id", (req, res) => {
if (req.body.completed === "on") {
req.body.completed = true
} else {
req.body.completed = false
}
Book.findByIdAndUpdate(
req.params.id,
req.body,
{
new: true,
},
(error, updatedBook) => {
res.redirect(`/books/${req.params.id}`)
}
)
})
Stop! Check your work!
Congratulations! We now have a Delete and Update feature! 🎉
Hopefully, you now have a fully functional CRUD app with a real MONGODB database.
Normally, this is the point where we would want to delete our seed route. If you want to comment it out, go ahead! But you might want to keep it in your app for future reference.