diff --git a/.gitignore b/.gitignore index 1dcef2d9..b5122114 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ node_modules -.env \ No newline at end of file +.env +.DS_Store +.vscode +settings.json \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index c3c81b8b..d04cfc83 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ -{ - "editor.fontSize": 42, - "terminal.integrated.fontSize": 62 -} \ No newline at end of file +// commented out original code, which increases font size. would be in .gitignore +// { +// "editor.fontSize": 42, +// "terminal.integrated.fontSize": 62 +// } \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index ff0eac39..542ecb6c 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,7 +1,9 @@ +// variables for spans in the li const deleteBtn = document.querySelectorAll('.fa-trash') const item = document.querySelectorAll('.item span') const itemCompleted = document.querySelectorAll('.item span.completed') +// 3 event listeners for each clickable span Array.from(deleteBtn).forEach((element)=>{ element.addEventListener('click', deleteItem) }) @@ -33,21 +35,28 @@ async function deleteItem(){ } } +// these two functions link to the put update on server side async function markComplete(){ + // parent node is li and span is the childNode (things that take up space makes this text 1 instead of 0) const itemText = this.parentNode.childNodes[1].innerText try{ const response = await fetch('markComplete', { method: 'put', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ + // get task span 'itemFromJS': itemText }) }) + // request body included in form data const data = await response.json() + // marked complete if successful console.log(data) + // refresh page and trigger get request location.reload() }catch(err){ + // give error if there is one console.log(err) } } @@ -59,14 +68,17 @@ async function markUnComplete(){ method: 'put', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ + // get task span 'itemFromJS': itemText }) }) const data = await response.json() console.log(data) + // refresh page and trigger get request location.reload() }catch(err){ + // give error if there is one console.log(err) } } \ No newline at end of file diff --git a/server.js b/server.js index 58b53e2f..80b53d61 100644 --- a/server.js +++ b/server.js @@ -1,93 +1,129 @@ +// import Express module from Node.js package manager (npm) const express = require('express') +// create an Express app const app = express() +// import MongoDb package. MongoClient class allows connections to be made to MongoDB const MongoClient = require('mongodb').MongoClient +// set endpoint for server, allowing it to listen for incoming client-side requests const PORT = 2121 require('dotenv').config() - +// initialize db (will assign value later when connecting to MongoDB database), dbConnectionStr (environment variable holding database connection string to connect to MongoDB database), and dbName (database name of 'todo') variables let db, dbConnectionStr = process.env.DB_STRING, dbName = 'todo' - +// connect to MongoDB database MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) .then(client => { + //console log name of database once connected console.log(`Connected to ${dbName} Database`) + // calls db() method on client object (usually MongoClient instance) and selects database by dbName. Assign matching object to db variable db = client.db(dbName) }) - +// set EJS (Embedded JavaScript) as the view engine in the express app app.set('view engine', 'ejs') +// middleware: serve static files (images, css, javascript) in the public folder app.use(express.static('public')) +// middleware: get data from request body, usually used for form submissions app.use(express.urlencoded({ extended: true })) +// middleware: parse JSON from req.body into JavaScript object (useful if clients send JSON from APIs) app.use(express.json()) +// when making get request from root route... +app.get('/', async (request, response) => { +// async/await option + // const todoItems = await db.collection('todos').find().toArray() + // const itemsLeft = await db.collection('todos').countDocuments({ completed: false }) + // response.render('index.ejs', { items: todoItems, left: itemsLeft }) -app.get('/',async (request, response)=>{ - const todoItems = await db.collection('todos').find().toArray() - const itemsLeft = await db.collection('todos').countDocuments({completed: false}) - response.render('index.ejs', { items: todoItems, left: itemsLeft }) - // db.collection('todos').find().toArray() - // .then(data => { - // db.collection('todos').countDocuments({completed: false}) - // .then(itemsLeft => { - // response.render('index.ejs', { items: data, left: itemsLeft }) - // }) - // }) - // .catch(error => console.error(error)) + // find collection called 'todos' in database and add documents to an array (which can hold objects) + db.collection('todos').find().toArray() + // pass resulting array into parameter data + .then(data => { + // + db.collection('todos').countDocuments({completed: false}) + .then(itemsLeft => { + // data (items AKA objects in arr) passed into EJS + response.render('index.ejs', { items: data, left: itemsLeft }) + }) + }) + .catch(error => console.error(error)) }) +// when making post request (linked to 'addTodo' action on form that made post request) from addTodo route app.post('/addTodo', (request, response) => { - db.collection('todos').insertOne({thing: request.body.todoItem, completed: false}) - .then(result => { - console.log('Todo Added') - response.redirect('/') - }) - .catch(error => console.error(error)) + // grab value from request body containing todoItem, add to database and give completed value of false + db.collection('todos').insertOne({ thing: request.body.todoItem, completed: false }) + .then(result => { + // console log for debugging + console.log('Todo Added') + // respond by refreshing & initiating get request + response.redirect('/') + }) + // console log error if there is one + .catch(error => console.error(error)) }) +// when making put request from markcomplete route (linked to 'markComplete' action on form) app.put('/markComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ + db.collection('todos').updateOne({ thing: request.body.itemFromJS }, { + // default is a false value for completed but this will now be set to true $set: { completed: true - } - },{ - sort: {_id: -1}, + } + }, { + sort: { _id: -1 }, + // if true, updating something that wouldn't there creates document for you with value entered upsert: false }) - .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') - }) - .catch(error => console.error(error)) + // respond with 'marked completed' in console log and respond as json + .then(result => { + console.log('Marked Complete') + response.json('Marked Complete') + }) + // return error if there is one + .catch(error => console.error(error)) }) +// when making put request from markUncomplete route (inked to 'markUncomplete' action) app.put('/markUnComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ + db.collection('todos').updateOne({ thing: request.body.itemFromJS }, { + // set value for completed to false $set: { completed: false - } - },{ - sort: {_id: -1}, + } + }, { + sort: { _id: -1 }, + // if true, updating something that wouldn't there creates document for you with value entered upsert: false }) - .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') - }) - .catch(error => console.error(error)) + .then(result => { + // respond with 'marked completed' in console log and respond as json + console.log('Marked Complete') + response.json('Marked Complete') + }) + //return error if there is one + .catch(error => console.error(error)) }) +// when making delete request from deleteItem route... app.delete('/deleteItem', (request, response) => { - db.collection('todos').deleteOne({thing: request.body.itemFromJS}) - .then(result => { - console.log('Todo Deleted') - response.json('Todo Deleted') - }) - .catch(error => console.error(error)) + // go to databas, find property with matching thing property, and delete + db.collection('todos').deleteOne({ thing: request.body.itemFromJS }) + .then(result => { + // respond with todo deleted + console.log('Todo Deleted') + response.json('Todo Deleted') + }) + // return error if there is one + .catch(error => console.error(error)) }) -app.listen(process.env.PORT || PORT, ()=>{ +// set up Express app to listen for requests on a specific port +// PORT variable is set by us but process.env.PORT is the PORT environment variable, which can be set on the server where the app is running (usually when deploying to another platform) +app.listen(process.env.PORT || PORT, () => { console.log(`Server running on port ${PORT}`) }) \ No newline at end of file diff --git a/views/index.ejs b/views/index.ejs index a26617ae..b37240b5 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -19,14 +19,19 @@

Todo List:

+