Error: throw er; // Unhandled 'error' event
TypeError: Cannot read properties of null (reading 'items') at C:\Users\shiva\Desktop\Web Development\todolist\app.js:105:17
getting the error in the 1st app.post method -> else statement. stuck at it for almost a day. ps: code might not run as db link is changed by me
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const _ = require("lodash");
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static("public"));
mongoose.connect("mongodb srv://adminshivam:[email protected]/todolistDB");
const itemsSchema = {
name: String
};
const Item = mongoose.model("Item", itemsSchema);
const item1 = new Item({
name: "Welcome to your todolist!"
});
const item2 = new Item({
name: "Hit the button to add a new item."
});
const item3 = new Item({
name: "<-- Hit this to delete an item."
});
const defaultItems = [item1, item2, item3];
const listSchema = {
name: String,
items: [itemsSchema]
};
const List = mongoose.model("List", listSchema);
app.get("/", function(req, res) {
Item.find({}, function(err, foundItems){
if (foundItems.length === 0) {
Item.insertMany(defaultItems, function(err){
if (err) {
console.log(err);
} else {
console.log("Successfully savevd default items to DB.");
}
});
res.redirect("/");
} else {
res.render("list", {listTitle: "Today", newListItems: foundItems});
}
});
});
app.get("/:customListName", function(req, res){
const customListName = _.capitalize(req.params.customListName);
List.findOne({name: customListName}, function(err, foundList){
if (!err){
if (!foundList){
//Create a new list
const list = new List({
name: customListName,
items: defaultItems
});
list.save();
res.redirect("/" customListName);
} else {
//Show an existing list
res.render("list", {listTitle: foundList.name, newListItems: foundList.items});
}
}
});
});
app.post("/", function(req, res){
const itemName = req.body.newItem;
const listName = req.body.list;
const item = new Item({
name: itemName
});
if (listName === "Today"){
item.save();
res.redirect("/");
} else {
List.findOne({name: listName}, function(err, foundList){
foundList.items.push(item);
foundList.save();
res.redirect("/" listName);
});
}
});
app.post("/delete", function(req, res){
const checkedItemId = req.body.checkbox;
const listName = req.body.listName;
if (listName === "Today") {
Item.findByIdAndRemove(checkedItemId, function(err){
if (!err) {
console.log("Successfully deleted checked item.");
res.redirect("/");
}
});
} else {
List.findOneAndUpdate({name: listName}, {$pull: {items: {_id: checkedItemId}}}, function(err, foundList){
if (!err){
res.redirect("/" listName);
}
});
}
});
app.get("/about", function(req, res){
res.render("about");
});
app.listen(3000, function() {
console.log("Server started on port 3000");
});
error link from above code
foundList.items.push(item);
list.ejs
<%- include("header") -%>
<div id="heading">
<h1> <%= listTitle %> </h1>
</div>
<div >
<% newListItems.forEach((listItem) => { %>
<form action="/delete" method="post">
<div >
<input type="checkbox" name="checkbox" value="<%= listItem._id %>" onChange="this.form.submit()">
<p><%= listItem.name %></p>
</div>
<input type="hidden" name="listName" value="<%= listTitle %>"></input>
</form>
<% });%>
<form action="/" method="post">
<input type="text" name="newItem" placeholder="New Item" autocomplete="off">
<button type="submit" name="list" value="<%= listTitle %> "> </button>
</form>
</div>
<%- include("footer") -%>
CodePudding user response:
The problem seems to be at your schema, you are not making it the right way, instead of passing an object to moongose.model
like this:
const itemsSchema = {
name: String
};
const Item = mongoose.model("Item", itemsSchema);
You should create a schema with the class Schema
from mongoose, so try the following:
const mongoose = require("mongoose");
const { Schema } = mongoose
const itemsSchema = new Schema({
name: {type: String, required: true}
})
const Item = mongoose.model("Item", itemsSchema)
And in your listSchema
do the following:
// removed const defaultItems = [item1, item2, item3];
const listSchema = new Schema({
name: {type: String, required: true},
// define an array of id that references the Item schema
items: [{type: ObjectId, ref: "Item", required: true, default: [] }]
});
const List = mongoose.model("List", listSchema);
// the object named as list1 will contain a reference to id of item1, item2 and item3.
const list1 = new List({name: "list1", items: [item1._id, item2._id, item3._id]}).save()
Further up, in your post api
:
app.post("/", async function(req, res){
const itemName = req.body.newItem;
const listName = req.body.list;
try {
const item = new Item({ name: itemName });
if (listName === "Today") {
await item.save();
res.redirect("/");
} else {
// save the item id to items field from list schema
const list = await List.findOne({ name: listName })
list.items.push(item._id)
await list.save()
// don't make a redirect within the database query
res.redirect("/" listName);
}
} catch(err) {
// If some error was threw handle it here
// you can handle mongoose errors as follow:
if(err instanceof mongoose.Error) {
// use a custom message or err.message
res.status(500).json({message: "error with Db"})
}
res.status(500).json({message: "something went wrong"})
}
});
See the docs to know more about it, as you are using references between your schemas I suggest you to take a look at the populate method because probably you will need it in the future. See the available queries from mongoose as well, almost everything you need is at the docs. Hope I helped you!