TodoList应用添加项失败、跳转异常及TypeError错误排查解决
解决Express+MongoDB TodoList应用的三个核心问题
问题1:无法向当前列表添加项目
错误原因
- 默认列表(Today)的添加逻辑中,变量名误用:创建的Item实例是
item,但保存时调用了未定义的newItem.save(),导致保存失败。 - 自定义列表的保存操作未等待异步完成就直接跳转,可能导致数据未持久化到数据库。
修复方法
- 将默认列表中的
newItem.save()改为item.save(),并在异步保存完成后再执行跳转。 - 自定义列表中,将跳转逻辑放在
foundList.save()的回调函数内,确保数据保存成功后再刷新页面。
问题2:添加项目后无法正确跳转
错误原因
- 自定义列表创建时,
list.save()是异步操作,未等待完成就执行res.redirect,此时数据库中可能还未生成新列表,导致跳转后找不到对应页面。 - 自定义列表添加项目时,同样未等待
foundList.save()完成就跳转,可能出现数据未更新就刷新页面的情况。
修复方法
- 列表创建时,在
list.save()的then回调中执行跳转。 - 项目添加完成后,确保在保存操作的回调内执行跳转逻辑。
问题3:偶尔抛出「TypeError: Cannot read properties of null (reading 'items')」错误
错误原因
- 自定义列表添加项目时,
List.findOne({ name: listName })可能返回null(比如列表名被篡改或已被删除),此时直接访问foundList.items会触发空指针错误。
修复方法
- 在操作
foundList之前增加存在性判断,若未找到列表则跳转回首页或提示错误。
修复后的完整代码
app.js
//jshint esversion:6 const express = require("express"); const bodyParser = require("body-parser"); const mongoose = require("mongoose"); const app = express(); app.set("view engine", "ejs"); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static("public")); mongoose.connect("mongodb://127.0.0.1:27017/todolistDB", { useNewUrlParser: true, useUnifiedTopology: true, }); 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() .then(function (foundItems) { if (foundItems.length === 0) { Item.insertMany(defaultItems) .then(function () { console.log("Successfully added default items to the DB."); res.redirect("/"); }) .catch(function (err) { console.log(err); }); } else { res.render("list", { listTitle: "Today", newListItems: foundItems }); } }) .catch(function (err) { console.log(err); }); }); app.get("/:customListName", function(req,res) { const customListName = req.params.customListName; List.findOne({name: customListName}).then(function(foundList) { if (!foundList) { // 创建新列表 const list = new List({ name: customListName, items: defaultItems }); list.save().then(() => { console.log("Successfully created new list."); res.redirect("/" + customListName); }).catch(err => { console.log(err); res.redirect("/"); }); } else { // 展示已存在的列表 res.render("list", {listTitle: foundList.name, newListItems: foundList.items}); } }).catch(function(err) { console.log(err); res.redirect("/"); }); }); 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().then(() => { console.log("Successfully added item to Today list."); res.redirect("/"); }).catch(err => { console.log(err); res.redirect("/"); }); } else { List.findOne({ name: listName }) .then((foundList) => { if (!foundList) { console.log("List not found:", listName); return res.redirect("/"); } foundList.items.push(item); foundList.save().then(() => { console.log("Successfully added item to custom list."); res.redirect("/" + listName); }).catch(err => { console.log(err); res.redirect("/"); }); }).catch((err) => { console.log(err); res.redirect("/"); }); } }); app.post("/delete", function(req, res) { const checkedItemId = req.body.checkbox; const listName = req.body.list; if (listName === "Today") { Item.findByIdAndRemove(checkedItemId).then(() => { console.log("Successfully removed item from Today list."); res.redirect("/"); }).catch(err => { console.log(err); res.redirect("/"); }); } else { List.findOneAndUpdate( { name: listName }, { $pull: { items: { _id: checkedItemId } } } ).then(() => { console.log("Successfully removed item from custom list."); res.redirect("/" + listName); }).catch(err => { console.log(err); res.redirect("/"); }); } }) app.get("/about", function (req, res) { res.render("about"); }); app.listen(3000, function () { console.log("Server started on port 3000"); });
list.ejs(同步修复自定义列表删除功能)
<%- include("header") -%> <div class="box" id="heading"> <h1><%= listTitle %></h1> </div> <div class="box"> <% newListItems.forEach(function(item){ %> <form action="/delete" method="post"> <div class="item"> <input type="checkbox" name="checkbox" value="<%= item._id %>" onchange="this.form.submit()" /> <input type="hidden" name="list" value="<%= listTitle %>"> <p><%= item.name %></p> </div> </form> <% }); %> <form class="item" 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") -%>
内容的提问来源于stack exchange,提问作者Jaydip_Baraiya
相关产品推荐
相关产品推荐

