Skip to content

Commented all non-dependency related code #863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# ensure node_modules is not sent to github (a lot of data and it already exists in browsers environment)
node_modules
# ensure any of your environment variables are excluded from being pushed to github (could contain private info)
.env
6 changes: 4 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// tryna mess with us

{
"editor.fontSize": 42,
"terminal.integrated.fontSize": 62
"editor.fontSize": 14,
"terminal.integrated.fontSize": 14
}
3 changes: 3 additions & 0 deletions public/css/style.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* make the heading red */
h1{
color: red;
}

/* text with a completed task will be colored gray and have a line thru it */
.completed{
color: gray;
text-decoration: line-through;
Expand Down
38 changes: 38 additions & 0 deletions public/js/main.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,109 @@
// find all delete icons
const deleteBtn = document.querySelectorAll('.fa-trash')
// find all instances of a span within any class="item" element
const item = document.querySelectorAll('.item span')
// find all instances of a completed span within any class="item" element
const itemCompleted = document.querySelectorAll('.item span.completed')

// for all instances of the delete icon, give it a click listener to call deleteItem
Array.from(deleteBtn).forEach((element)=>{
element.addEventListener('click', deleteItem)
})

// for all instances of spans within class="item" elements, give it a click listener to call markComplete
Array.from(item).forEach((element)=>{
element.addEventListener('click', markComplete)
})

// for all instances of completed items within class="item" elements, give it a click listener to markUnComplete
Array.from(itemCompleted).forEach((element)=>{
element.addEventListener('click', markUnComplete)
})

// create an async function to delete items
async function deleteItem(){
// access the parent node of a clicked icon, find its second child's inner text
const itemText = this.parentNode.childNodes[1].innerText
try{
// attempt to send request to server to delete the item, 'deleteItem' is the endpoint used in this case
const response = await fetch('deleteItem', {
// notify server which method is supposed to be used
method: 'delete',
// tell the server to type of content to expect
headers: {'Content-Type': 'application/json'},
// create an object whose property and value can be accessed by the server, and format it into json
body: JSON.stringify({
'itemFromJS': itemText
})
})
// take the data the server responded with and format is as an object
const data = await response.json()
// log the data so we can see what exactly is sent back in the console
console.log(data)
// reload the current location so the most up to date content is shown
location.reload()

// if the server is not accepting or properly returning the requested info, tell us why
}catch(err){
console.log(err)
}
}

// create an async function to mark tasks as completed
async function markComplete(){
// find the parent node of the content that was clicked, get the text content of its second child
const itemText = this.parentNode.childNodes[1].innerText
// attempt to send request to server to update the data
try{
// create a variable to ensure the request is properly received, 'markComplete' tells the server which endpoint to use
const response = await fetch('markComplete', {
// notify the server which method is supposed to be used
method: 'put',
// let the server know what type of content to expect
headers: {'Content-Type': 'application/json'},
// create an object and format as json it so the server can use it
body: JSON.stringify({
'itemFromJS': itemText
})
})
// convert the server's response into json format
const data = await response.json()
// log the data received
console.log(data)
// reload the location with the most up to date data
location.reload()

// if there was any error during this process, log the error
}catch(err){
console.log(err)
}
}

// make an async function to mark completed tasks as incomplete
async function markUnComplete(){
// find the parent node of the clicked content, get the inner text of its second child
const itemText = this.parentNode.childNodes[1].innerText
// attempt to send request to server to update data
try{
// set variable to make request, 'markUnComplete' tells the server which endpoint to use
const response = await fetch('markUnComplete', {
// tell the server which method to use
method: 'put',
// tell the server which type of content to expect
headers: {'Content-Type': 'application/json'},
// create an object with the text and format it with json so the server can use it
body: JSON.stringify({
'itemFromJS': itemText
})
})
// convert the server's response into json format
const data = await response.json()
// log the data received from the server
console.log(data)
// reload the location
location.reload()

// if there were any issues during the update process, log the issue
}catch(err){
console.log(err)
}
Expand Down
63 changes: 60 additions & 3 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,51 @@
// import express and mongo (after npm install express, mongodb) and create an instance of MongoClient
const express = require('express')
const app = express()
const MongoClient = require('mongodb').MongoClient
// set up port
const PORT = 2121
// install dotenv to secure information (place in gitignore)
require('dotenv').config()


// declare the db
let db,
// receive the connection string (obtained from mongo db) that is stored in the (gitignored) env
dbConnectionStr = process.env.DB_STRING,
// name your app after the app name in Mongo Atlas
dbName = 'todo'

// connect using the connection string and an object and add Unified Topology for UX (tho now standard)
MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true })
// take the return from the connect method's Promise
.then(client => {
// let us know we're connected to the database
console.log(`Connected to ${dbName} Database`)
// set the pre-declared, global db to the clients proper database
db = client.db(dbName)
})


// enable use of ejs templating language (npm install ejs --save)
app.set('view engine', 'ejs')
// tell our instance of express to be consistently viewing the public folder
app.use(express.static('public'))
// make sure the instance of express can handle html form submissions
app.use(express.urlencoded({ extended: true }))
// make sure our instance of express can handle the json format
app.use(express.json())


// upon loading the main page '/', call an async function to retrieve information
app.get('/',async (request, response)=>{
// go into our database's collection thats named 'todos', everything within it, and put it in an array
const todoItems = await db.collection('todos').find().toArray()
// access the same collection, get a total number of documents that have a property of completed that = false
const itemsLeft = await db.collection('todos').countDocuments({completed: false})
// send the response to the browser as an object - with properties item = the array from above, and left = number of incomplete
response.render('index.ejs', { items: todoItems, left: itemsLeft })



// this performs the same as above for the itemsLeft, but does it in the form of Promise chaining. items: data -> items: todoItems

// db.collection('todos').find().toArray()
// .then(data => {
// db.collection('todos').countDocuments({completed: false})
Expand All @@ -35,59 +56,95 @@ app.get('/',async (request, response)=>{
// .catch(error => console.error(error))
})

// when our instance of express hears a POST request thats made with the /addTodo action property
app.post('/addTodo', (request, response) => {
// find our collection called todos and insert an object with properties thing = the request body's todoItem and completed = false
db.collection('todos').insertOne({thing: request.body.todoItem, completed: false})
// if a message is sent from the database after the insertion, obtain the 'result' of that message
.then(result => {
// ignore the resulting message and log in real language what occurred
console.log('Todo Added')
// redirect to the main page
response.redirect('/')
})
// if an error occurred at any point, log it
.catch(error => console.error(error))
})

// set up our instance of express to receive a PUT request thats made with the /markComplete action
app.put('/markComplete', (request, response) => {
// go to our db's todo collection and update one object that has the thing property that matches the request body's itemFromJS
db.collection('todos').updateOne({thing: request.body.itemFromJS},{
// let mongo db know were planning to set (change) something on that object
$set: {
// change its completed property to true
completed: true
}
},{
// sort the objects in descending order (newest to oldest)
sort: {_id: -1},
// don't add another task if the one searched for isnt found
upsert: false
})
// if mongo sends a response to that process, get it
.then(result => {
// ignore result
// log real language completion of task
console.log('Marked Complete')
// send the plain english response as a json
response.json('Marked Complete')
})
// if theres an error, tell us whats happening
.catch(error => console.error(error))

})

// set up the instance of express to receive a PUT requests made to the /markUnComplete endpoint
app.put('/markUnComplete', (request, response) => {
// see above, access collection and update and object with same prop values
db.collection('todos').updateOne({thing: request.body.itemFromJS},{
// were setting / changing something
$set: {
// its fake news now
completed: false
}
},{
// sort newest to oldest
sort: {_id: -1},
// dont repeat
upsert: false
})
// get return from mongo
.then(result => {
// ignore that return
// log to server
console.log('Marked Complete')
// send to browser
response.json('Marked Complete')
})
// what went wrong?
.catch(error => console.error(error))

})

// set up the server to handle DELETE requests made with the /deleteItem endpoint
app.delete('/deleteItem', (request, response) => {
// access the db collection named todo and delete an item in it that has the thing property equal to the request body's itemFromJS
db.collection('todos').deleteOne({thing: request.body.itemFromJS})
// get mongos return as a result
.then(result => {
// ignore it
// log to the server that it was deleted
console.log('Todo Deleted')
// tell the browser it was deleted
response.json('Todo Deleted')
})
// tells us what went wrong if something did
.catch(error => console.error(error))

})

// tell the server to listen to the environment's port, or if its unavailable (only hosted locally) to listen at our pre-established local port
app.listen(process.env.PORT || PORT, ()=>{
console.log(`Server running on port ${PORT}`)
})
18 changes: 17 additions & 1 deletion views/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,46 @@
<title>Document</title>
</head>
<body>
<!-- Create To-Do List with basic HTML in an ejs file -->
<h1>Todo List: </h1>
<ul class="todoItems">
<!-- Since we know that we will need to iterate thru a fetched array (items) embed js code into html template using <% JS %> -->
<% for(let i=0; i < items.length; i++) {%>
<li class="item">
<!-- for each item checked from prior array, see if its completed -->
<% if(items[i].completed === true) {%>
<!-- if its completed, give it the completed class (for styling) and add as a list item -->
<!-- insertion done via use of <%= variable %> -->
<span class='completed'><%= items[i].thing %></span>
<!-- for all items that fail the completed check -->
<% }else{ %>
<!-- simply put it in the list as a list item (no class), also via <%= variable %> -->
<span><%= items[i].thing %></span>
<% } %>
<!-- Close the if/else check -->
<% } %>
<!--add a delete button -->
<span class='fa fa-trash'></span>
</li>
<!-- close the for loop -->
<% } %>
</ul>

<!-- take rendered left variable, and insert it within the Left to do heading -->
<h2>Left to do: <%= left %></h2>

<h2>Add A Todo:</h2>

<!-- set up a form to submit new tasks -->
<!-- /addTodo tells it which endpoint to use, POST tells it which method to use -->
<form action="/addTodo" method="POST">
<!-- input text content of task, provide 'hint', label with a name for use in backend -->
<input type="text" placeholder="Thing To Do" name="todoItem">
<!-- create button to submit entirety of form's inputs -->
<input type="submit">
</form>


<!-- link to public functionality page -->
<script src='js/main.js'></script>
</body>
</html>