diff --git a/public/css/style.css b/public/css/style.css index 0475253a..78a904e8 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -1,7 +1,8 @@ -h1{ - color: red; -} -.completed{ - color: gray; - text-decoration: line-through; -} \ No newline at end of file +h1{ /* selects the h1 tag in the ejs file and sets style properties for it */ + color: red; /* makes the text color red */ +} /* closes h1 tag selector */ + +.completed{ /* selects items with a class of completed in the ejs file */ + color: gray; /* makes text color gray */ + text-decoration: line-through; /* displays text with a strikethrough line */ +} /* closes selector for this custom class */ \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index ff0eac39..dc994127 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,72 +1,71 @@ -const deleteBtn = document.querySelectorAll('.fa-trash') -const item = document.querySelectorAll('.item span') -const itemCompleted = document.querySelectorAll('.item span.completed') +const deleteBtn = document.querySelectorAll('.fa-trash') /* stores all the delete icon elements from the dom into a variable */ +const item = document.querySelectorAll('.item span') /* stores todo list items from the DOM into a variable */ +const itemCompleted = document.querySelectorAll('.item span.completed') /* collects all the completed items from the DOM */ -Array.from(deleteBtn).forEach((element)=>{ - element.addEventListener('click', deleteItem) -}) +Array.from(deleteBtn).forEach((element)=>{ /* creates an array from deleteBtn and loops through each element */ + element.addEventListener('click', deleteItem) /* adds a click event listener and calls the deleteItem function */ +}) /* closes for loop */ -Array.from(item).forEach((element)=>{ - element.addEventListener('click', markComplete) -}) +Array.from(item).forEach((element)=>{ /* turns item into an array and loops through each element */ + element.addEventListener('click', markComplete) /* adds an event listener for clicks and calls the markComplete function */ +}) /* closes loop */ -Array.from(itemCompleted).forEach((element)=>{ - element.addEventListener('click', markUnComplete) -}) +Array.from(itemCompleted).forEach((element)=>{ /* turns itemCompleted into an array and loops through each element */ + element.addEventListener('click', markUnComplete) /* adds an event listener to each completed element and calls markUnComplete function */ +}) /* closes loop */ -async function deleteItem(){ - const itemText = this.parentNode.childNodes[1].innerText - try{ - const response = await fetch('deleteItem', { - method: 'delete', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - 'itemFromJS': itemText - }) - }) - const data = await response.json() - console.log(data) - location.reload() +async function deleteItem(){ /* declares an async function */ + const itemText = this.parentNode.childNodes[1].innerText /* looks in the list item and saves the todo item text in a variable */ + try{ /* once a response is received run the try block */ + const response = await fetch('deleteItem', { /* stores response for the deleteItem route in a variable */ + method: 'delete', /* the CRUD operation used */ + headers: {'Content-Type': 'application/json'}, /* specifies the content will be JSON format */ + body: JSON.stringify({ /* convert the data into a string */ + 'itemFromJS': itemText /* storing the inner text of the todo item with a key of itemFromJS */ + }) /* closing the body block */ + }) /* closing the response object */ + const data = await response.json() /* saving the server response as JSON */ + console.log(data) /* print the promise to the console */ + location.reload() /* refresh the page with the data received */ - }catch(err){ - console.log(err) - } -} + }catch(err){ /* retain any errors that occur into the catch block */ + console.log(err) /* print those errors to the console */ + } /* close error catch block */ +} /* close async function block */ -async function markComplete(){ - const itemText = this.parentNode.childNodes[1].innerText - try{ - const response = await fetch('markComplete', { - method: 'put', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - 'itemFromJS': itemText - }) - }) - const data = await response.json() - console.log(data) - location.reload() +async function markComplete(){ /* declares an async function */ + const itemText = this.parentNode.childNodes[1].innerText /* looks into the list item and saves the text in a variable */ + try{ /* starting a try block */ + const response = await fetch('markComplete', { /* stores fetch response for the markComplete route in a variable */ + method: 'put', /* setting the CRUD method used */ + headers: {'Content-Type': 'application/json'}, /* indicates the data format used (JSON) */ + body: JSON.stringify({ /* turn the response into a string and storing it under a key of body */ + 'itemFromJS': itemText /* storing the actual text in a key that can be called */ + }) /* closing the body object block */ + }) /* closing the fetch response block */ + const data = await response.json() /* saving the JSON confirmation of the update that we are waiting for */ + console.log(data) /* printing the updated response to the console */ + location.reload() /* refreshing the page with the updated response */ + }catch(err){ /* save any errors and use in this catch block */ + console.log(err) /* print errors to the console */ + } /* close the catch block */ +} /* close the async function block */ - }catch(err){ - console.log(err) - } -} +async function markUnComplete(){ /* declaring an async function */ + const itemText = this.parentNode.childNodes[1].innerText /* looks into the list item span and saves the text in a variable */ + try{ /* starting a try block */ + const response = await fetch('markUnComplete', { /* saving the fetch response to the markUnComplete route as a variable */ + method: 'put', /* sets the CRUD method to update */ + headers: {'Content-Type': 'application/json'}, /* sets the content type as JSON */ + body: JSON.stringify({ /* turn the JSON response into a string */ + 'itemFromJS': itemText /* save the string text in a key of itemFromJS */ + }) /* close the body block */ + }) /* close the object */ + const data = await response.json() /* store the JSON message confirming the update in a variable */ + console.log(data) /* print the result to the console */ + location.reload() /* refresh the page with updated data displayed */ -async function markUnComplete(){ - const itemText = this.parentNode.childNodes[1].innerText - try{ - const response = await fetch('markUnComplete', { - method: 'put', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - 'itemFromJS': itemText - }) - }) - const data = await response.json() - console.log(data) - location.reload() - - }catch(err){ - console.log(err) - } -} \ No newline at end of file + }catch(err){ /* save any errors that occur */ + console.log(err) /* print those errors to the console */ + } /* close catch block */ +} /* close async function block */ \ No newline at end of file diff --git a/server.js b/server.js index 58b53e2f..7b2c1322 100644 --- a/server.js +++ b/server.js @@ -1,30 +1,31 @@ -const express = require('express') -const app = express() -const MongoClient = require('mongodb').MongoClient -const PORT = 2121 -require('dotenv').config() +const express = require('express') // allows us to use express methods in this file +const app = express() // executes an instance of express in app variable +const MongoClient = require('mongodb').MongoClient // provides access to database methods (within MongoClient class) and to interact with MongoDB items +const PORT = 2121 // saves the port location where our server is listening +require('dotenv').config() // connects the .env file so we can use the database key/link without exposing our password. +let db, /* set up a variable for the database in the glocal scope */ + dbConnectionStr = process.env.DB_STRING, /* store connection string from .env file in a variable */ + dbName = 'todo' /* save the name of our database to pass along to MongoClient */ -let db, - dbConnectionStr = process.env.DB_STRING, - dbName = 'todo' - -MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) - .then(client => { - console.log(`Connected to ${dbName} Database`) - db = client.db(dbName) - }) +MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true }) /* connect to the MongoDB with the connection string & an additional property (using MongoDB driver's new connection management engine set to false by default). We are establishing a promise here */ + .then(client => { /* pass in client information back to the server once we get a promise response (which confirms a connection) */ + console.log(`Connected to ${dbName} Database`) /* use a template literal to print a confirmation message to console with the specific database name we created */ + db = client.db(dbName) /* store the database information we are getting in an instance of the client factory method in a previously declared variable */ + }) /* closing the .then */ -app.set('view engine', 'ejs') -app.use(express.static('public')) -app.use(express.urlencoded({ extended: true })) -app.use(express.json()) +/* Middleware methods we are using: Express */ +app.set('view engine', 'ejs') /* setting the ejs format as the default render to view our page */ +app.use(express.static('public')) /* sets the default location folder for static assets like style.css and main.js */ +app.use(express.urlencoded({ extended: true })) /* tells express to decode and encode url's where the header matched the content. Supports arrays and objects as well (extended) */ +app.use(express.json()) /* replaces bodyparser; parses json content from incoming requests */ + +app.get('/',async (request, response)=>{ /* starts an asynchronous GET method when the root route is passed in, sets up request and response parameters */ + const todoItems = await db.collection('todos').find().toArray() /* awaits and stores all items in the database todos collection in an array */ + const itemsLeft = await db.collection('todos').countDocuments({completed: false}) /* awaits the number of uncompleted tasks and stores it */ + response.render('index.ejs', { items: todoItems, left: itemsLeft }) /* send the items and the count in an object to the ejs file so it can be rendered correctly, and render the EJS file */ -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}) @@ -35,59 +36,56 @@ app.get('/',async (request, response)=>{ // .catch(error => console.error(error)) }) -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)) -}) +app.post('/addTodo', (request, response) => { /* uses an express POST method to create a new item using the route we are passing in from our EJS form */ + db.collection('todos').insertOne({thing: request.body.todoItem, completed: false}) /* finds the todos collection in the database and inserts a new todo item with a completed property of false */ + .then(result => { /* execute a response once we have confirmation that the item has been added */ + console.log('Todo Added') /* print a confirmation message to the console */ + response.redirect('/') /* respond by getting rid of the /addTodo route and then redirects to the root route, refreshing the page */ + }) /* closing the then response actions */ + .catch(error => console.error(error)) /* print errors to the console */ +}) /* close the post action */ -app.put('/markComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: true - } - },{ - sort: {_id: -1}, - upsert: false - }) - .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') - }) - .catch(error => console.error(error)) - -}) +app.put('/markComplete', (request, response) => { /* starts an express PUT method to change the completion property of a todo item in the database using the /markComplete route */ + db.collection('todos').updateOne({thing: request.body.itemFromJS},{ /* look in the database to find the todo passed in from main.js and then start a new object */ + $set: { /* setting a property value */ + completed: true /* change the completion status to true */ + } /* close set block */ + },{ /* start another object */ + sort: {_id: -1}, /* moves item to the bottom of the list */ + upsert: false /* says if item does not already exist then do not insert this one */ + }) /* closes this collection of properties */ + .then(result => { /* if the update was successful then execute this arrow function */ + console.log('Marked Complete') /* print a confirmation message to the console that the update was successful */ + response.json('Marked Complete') /* send a JSON message to the client side (main.js) that change was successful */ + }) /* */ + .catch(error => console.error(error)) /* an arrow function to print any errors to the console */ +}) /* closes the PUT method block */ -app.put('/markUnComplete', (request, response) => { - db.collection('todos').updateOne({thing: request.body.itemFromJS},{ - $set: { - completed: false - } - },{ - sort: {_id: -1}, - upsert: false - }) - .then(result => { - console.log('Marked Complete') - response.json('Marked Complete') - }) - .catch(error => console.error(error)) +app.put('/markUnComplete', (request, response) => { /* start a PUT method to update a todo item as an uncompleted task through the /markUnComplete route and then manage the request and response with an arrow function */ + db.collection('todos').updateOne({thing: request.body.itemFromJS},{ /* find the todo item in the database and update it with the properties inside an object we are passing in here */ + $set: { /* set a property */ + completed: false /* set the completed property to a false value */ + } /* close the set block */ + },{ /* start an object with further properties to pass in */ + sort: {_id: -1}, /* sort the todo item to be at the bottom of the list */ + upsert: false /* if the item is not there, do not insert it */ + }) /* close this set of properties */ + .then(result => { /* attempt this arrow function if the update is suceessful */ + console.log('Marked Uncomplete') /* print a completion message to the console */ + response.json('Marked Uncomplete') /* send a JSON message back to the client indicating the update was successful */ + }) /* close the then block */ + .catch(error => console.error(error)) /* save and print any errors to our console */ +}) /* close the PUT method */ -}) - -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)) - -}) +app.delete('/deleteItem', (request, response) => { /* start a DELETE method to handle the request and response triggered by the /deleteItem route */ + db.collection('todos').deleteOne({thing: request.body.itemFromJS}) /* find the specific todo item in the database to delete */ + .then(result => { /* if the delete is successful complete the actions in this arrow function */ + console.log('Todo Deleted') /* print a confirmation message to the console that the delete was successful */ + response.json('Todo Deleted') /* send a JSON message back to the client side confirming the delete was successful */ + }) /* close the then block */ + .catch(error => console.error(error)) /* save any errors and print them to the console */ +}) /* close the DELETE method */ -app.listen(process.env.PORT || PORT, ()=>{ - console.log(`Server running on port ${PORT}`) -}) \ No newline at end of file +app.listen(process.env.PORT || PORT, ()=>{ /* listen for a connection to the database at this saved port or the port of the .env file or deployment engine and then run an anonymous function */ + console.log(`Server running on port ${PORT}`) /* print confirmation message to the console indicating the port used */ +}) /* close listen block */ \ No newline at end of file diff --git a/views/index.ejs b/views/index.ejs index a26617ae..d25a2cf8 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -1,47 +1,38 @@ - - - - - - - Document - - - - - - - - - - - Document - - -

Todo List:

- + + + + + + + Document + + + + +

Todo List:

+ -

Left to do: <%= left %>

+

Left to do: <%= left %>

-

Add A Todo:

+

Add A Todo:

-
- - -
+
+ + +
- - - + + +