Section 27 – Lessons 361, 362, 363 and 364 – Complete 2020 Web Development Bootcamp

Lesson 361 – Deleting Items from ToDo List Database

In order to delete items that are checked as completed, the first step is to wrap the checkbox and its paragraph element in the list.ejs file in a form like this –

<form action="/delete" method="post">
        <div class="item">
        <input type="checkbox">
        <p><%=  item.name  %></p>
        </div>
      </form>

The action for the form is “/delete” and the method is “post”.

The complete list.ejs code is now –

<%- 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">
        <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">+</button>
      </form>
  </div>

<%- include("footer") -%>

The next step is to create a new “/delete” post route in the app.js file. The new post route looks like this –

app.post ("/delete", function(req, res) {
  console.log(req.body);
});

At this point this code doesn’t work because in the <input type=”checkbox”> code in the list.ejs file which causes a submit when the checkbox is checked.

To get the code to work, you add “onChange=”this.form.submit()” to the checkbox input element like this –

<input type="checkbox" onChange="this.form.submit()">

We also need to give the input checkbox element a name –

<input type="checkbox" name="checkbox" onChange="this.form.submit()">

The new app.post(“/delete”) method now console.logs the value “on”. What we want is the item name that was checked off.

In order to do this, the first step is to add a value to the input checkbox element. The value will be equal to an EJS selector. The new input checkbox element with the added value is –

<input type="checkbox" name="checkbox" value="<%=item._id%>" onChange="this.form.submit()">

Now the new app.post(“/delete”) route will console.log the id of the item which was checked.

The next change you make is to bind the id to a constant variable called “checkedItemId” like this –

const checkedItemId = req.body.checkbox;

The challenge is to remove the item from the database that has the id of the checked item.

To complete this challenge, you refactor the app.post(“/delete”) method using the findByIdAndDelete() method. The refactored code is –

app.post("/delete", function(req, res) {
  const checkedItemId = req.body.checkbox;
  Item.findByIdAndDelete(checkedItemId, function(err) {
    if (err) {
      console.log(err);
    } else {
      console.log("Successfully deleted item.");
    }
  })
  res.redirect("/");
});

Lesson 362 – Creating Custom Lists using Express Route Parameters

The challenge is to create a dynamic route parameter using Express and replace the app.get(“/work”) route with a dynamic route.

The first step is to create a new listsSchema and new List –

const listSchema = {
  name: String,
  items: [itemsSchema]
};

const List = mongoose.model("List", listSchema);

This is the the code for the dynamic route parameter that completes the challenge –

 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});
      }
    }
  });

})

Lesson 363 – Adding New Items to the Custom ToDo List

The first step in being able to add a new item to the custom ToDo list is to add a value to the button element in the list.ejs file. The value is an EJS script tag. The new button element with the added value looks like this –

<button type="submit" name="list" value="<%= listTitle %>">+</button>

Then in your app.js file inside the app.post(“/”) route, you create a new constant variable called “listName” like this –

const listName = req.body.list;

Then you create an if statement to check whether the list being added to is the “Today” list and if it is to save the new item to that list and redirect to that page. If it isn’t the “Today” list which is being added to then the new item is added to the name of the list specified in the browser and the user is redirected to that list. This is the code –

if (listName === "Today") {
    item.save();
    res.redirect("/");
  } else {
    List.findOne({name: listName}, function(err, foundList) {
      foundList.items.push(item);
      foundList.save();
      res.redirect("/" + listName);
    });

This is the code for the refactored app.post(“/”) route –

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);
    });
  }
});

Lesson 364 – Revisiting Lodash and Deleting Items from Custom ToDo Lists

The first step in being able to delete items from a custom list is to add another input element in the checkbox form. in the list.ejs file. The new input element will have a type of “hidden”, a name of “listName” and an EJS script tag as a value. This is the new input element –

<input type="hidden" name="listName" value="<%= listTitle %>"></input>

Next, in the app.post(“/delete”) route in the app.js file, you create a new constant variable called list name like this –

const listName = req.body.listName;

Then you need to use an if statement to check whether we are making a post request to delete an item from the default list where the name is “Today” or from a custom list. This is the refactored app.post(“/delete”) route code –

app.post("/delete", function(req, res) {
  const checkedItemId = req.body.checkbox;
  const listName = req.body.listName;

  if (listName === "Today") {
    Item.findByIdAndDelete(checkedItemId, function(err) {
    if (err) {
      console.log(err);
    } else {
      console.log("Successfully deleted item.");
    }
  })
  res.redirect("/");
 } else {
    List.findOneAndUpdate({name: listName}, {$pull: {items: {_id: checkedItemId}}}, function(err, foundList) {
      if (!err) {
        res.redirect("/" + listName);
      } 
    });
 }
});

The next step is to implement lodash so that when a user inputs a lower case custom list name, the first letter of the name is capitalized. This avoids the accidental creation of two custom lists – one with a lower case name and one with the first letter of the name capitalized.

The first step in implementing lodash is to create a constant which requires lodash like this –

const _ = require("lodash");

The next step is to use lodash in the app.get(“:/customListName”) route by refactoring the constant variable “customListName” like this –

const customListName = _.capitalize(req.params.customListName);

The refactored app.get(“:/customListName”) route code is –

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});
      }
    }
  });
});