skip to Main Content

Error: throw er; // Unhandled ‘error’ event

TypeError: Cannot read properties of null (reading ‘items’)
at C:UsersshivaDesktopWeb Developmenttodolistapp.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 class="box" id="heading">
        <h1> <%= listTitle %> </h1>
      </div>
    
      <div class="box">
        <% newListItems.forEach((listItem) => { %>
          <form action="/delete" method="post">
            <div class="item">
              <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 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") -%>

2

Answers


  1. 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:

    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!

    Login or Signup to reply.
  2. just remove the space in ejs file

    <button type="submit" name="list" value="<%= listTitle %>😒">+</button>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search