app.js
//jshint esversion:6
/* --------- 00. Basic Set Up ---------- */
const express = require("express");
const bodyParser = require("body-parser");
const _ = require("lodash");
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static("public"));
/* --------- 00. Set Up Mongoose / Schema / Model ---------- */
const mongoose = require("mongoose");
mongoose.connect("mongodb://localhost:27017/todolistDB")
const itemsSchema = new mongoose.Schema({
name: String
});
const Item = mongoose.model("Item", itemsSchema);
const workOut = new Item({
name: "work out"
});
const engListen = new Item({
name: "English Listen"
});
const engReading = new Item({
name: "English Reading"
});
const defaultItems = [workOut, engListen, engReading];
const listSchema = new mongoose.Schema({
name: String,
items: [itemsSchema]
})
const List = mongoose.model("List", listSchema);
/* --------- 01. Set the default Items ---------- */
app.get("/", function(req, res) {
Item.find(function(err, foundItems) {
// If there's nothing in the list
if (foundItems.length == 0) {
Item.insertMany(defaultItems, function(err) {
if (err) {
console.log(err);
} else {
console.log("Successful saved all items.");
}
});
res.redirect("/");
// If there's something in the list
} else {
res.render("list", {
listTitle: "Today",
newListItems: foundItems
});
}
})
});
/* --------- 02. Set the customr Lists ---------- */
app.get("/:customListName", function(req, res) {
// Auto capitalize the list names
customListName = _.capitalize(req.params.customListName);
// Check if there's already a list exist
List.findOne({
name: customListName
}, function(err, foundList) {
// If there's not a list with the name exist
if (!foundList) {
const customList = new List({
name: customListName,
items: defaultItems
});
// ** USE THE CALLBACK FUNCTION TO AVOID LOADING TO FAST
customList.save(function(err, result) {
res.redirect("/" + customListName);
});
// If there's already a list with the name exist
} else {
res.render("list", {
listTitle: foundList.name,
newListItems: foundList.items
});
}
});
})
/* --------- 03. Add a new item in a list ---------- */
app.post("/", function(req, res) {
const itemName = req.body.newItem;
const listName = req.body.list;
const newItem = new Item({
name: itemName
});
// If it's add in the default list
if (listName == "Today") {
newItem.save();
res.redirect("/");
// If it's add in custom list
} else {
List.findOne({
name: listName
}, function(err, foundList) {
// ** USE PUSH FUNCTION TO ADD IN A LIST
foundList.items.push(newItem);
foundList.save();
res.redirect("/" + listName)
})
}
});
/* --------- 04. Delete an item in the list ---------- */
app.post("/delete", function(req, res) {
const checkedItemId = req.body.checkbox;
const listName = req.body.listName;
// If the item is in default list
if (listName == "Today") {
Item.findByIdAndRemove(checkedItemId, function(err) {
if (!err) {
console.log("successful");
};
});
res.redirect("/");
// If the item is in custom list
} else {
// ** findOneAndUpdate function with 3 inputs:
// 1. condition => find the List with name listName
// 2. update
// a. $pull the item out of list => items
// b. the pulled out item with id => checkedItemId
// 3. callback function => (err, foundList in condition)
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");
});
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">
<!-- checkbox: use onCharge attr to check if checkbox is change, then submit => POST REQUEST -->
<!-- Add Name & Value: let app.js know what item is been checked -->
<input type="checkbox" name="checkbox" value="<%= item._id %>" onChange="this.form.submit()">
<p><%= item.name %></p>
</div>
<!-- hidden input: send the message back with invisible at front end -->
<input type="hidden" name="listName" value="<%= listTitle %>">
</form>
<% }) %>
<form class="item" action="/" method="post">
<!-- autocomplete attr: Not to show the auto keyin box -->
<input type="text" name="newItem" placeholder="New Item" autocomplete="off">
<button type="submit" name="list" value="<%= listTitle %>">+</button>
</form>
</div>
<%- include("footer") -%>