Skip to content
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
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"editor.fontSize": 42,
"terminal.integrated.fontSize": 62
"editor.fontSize": 14,
"terminal.integrated.fontSize": 14
}
82 changes: 63 additions & 19 deletions public/js/main.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,116 @@
// Selects all delete buttons on the page
const deleteBtn = document.querySelectorAll('.fa-trash')

// Selects all to-do items
const item = document.querySelectorAll('.item span')

// Selects all completed to-do items
const itemCompleted = document.querySelectorAll('.item span.completed')

Array.from(deleteBtn).forEach((element)=>{
// Adds a click event to each delete button
// When clicked, it runs the deleteItem function
Array.from(deleteBtn).forEach((element) => {
element.addEventListener('click', deleteItem)
})

Array.from(item).forEach((element)=>{
// Adds a click event to each incomplete to-do item
// When clicked, it runs the markComplete function
Array.from(item).forEach((element) => {
element.addEventListener('click', markComplete)
})

Array.from(itemCompleted).forEach((element)=>{
// Adds a click event to each completed to-do item
// When clicked, it runs the markUnComplete function
Array.from(itemCompleted).forEach((element) => {
element.addEventListener('click', markUnComplete)
})

async function deleteItem(){
// Deletes a to-do item
async function deleteItem() {
// Gets the text of the selected to-do item
const itemText = this.parentNode.childNodes[1].innerText
try{

try {
// Sends a DELETE request to the server
const response = await fetch('deleteItem', {
method: 'delete',
headers: {'Content-Type': 'application/json'},
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
'itemFromJS': itemText
'itemFromJS': itemText
})
})
})

// Converts the server response to JSON
const data = await response.json()

// Displays the response in the console
console.log(data)

// Reloads the page so the deleted item disappears
location.reload()

}catch(err){
} catch (err) {
// Logs any errors to the console
console.log(err)
}
}

async function markComplete(){
// Marks a to-do item as complete
async function markComplete() {
// Gets the text of the selected to-do item
const itemText = this.parentNode.childNodes[1].innerText
try{

try {
// Sends a PUT request to the server to mark the item complete
const response = await fetch('markComplete', {
method: 'put',
headers: {'Content-Type': 'application/json'},
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
'itemFromJS': itemText
})
})
})

// Converts the server response to JSON
const data = await response.json()

// Displays the response in the console
console.log(data)

// Reloads the page to show the item as completed
location.reload()

}catch(err){
} catch (err) {
// Logs any errors to the console
console.log(err)
}
}

async function markUnComplete(){
// Marks a completed to-do item as incomplete
async function markUnComplete() {
// Gets the text of the selected completed item
const itemText = this.parentNode.childNodes[1].innerText
try{

try {
// Sends a PUT request to the server to mark the item as incomplete
const response = await fetch('markUnComplete', {
method: 'put',
headers: {'Content-Type': 'application/json'},
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
'itemFromJS': itemText
})
})
})

// Converts the server response to JSON
const data = await response.json()

// Displays the response in the console
console.log(data)

// Reloads the page to show the item as incomplete
location.reload()

}catch(err){
} catch (err) {
// Logs any errors to the console
console.log(err)
}
}
129 changes: 102 additions & 27 deletions server.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,59 @@

// Imports the Express framework
const express = require('express')

// Creates an Express application
const app = express()

// Imports the MongoDB client
const MongoClient = require('mongodb').MongoClient

// Sets the default port for the server
const PORT = 2121
require('dotenv').config()

// Loads environment variables from the .env file
require('dotenv').config()

// Creates variables for the database connection and database name
let db,
dbConnectionStr = process.env.DB_STRING,
dbName = 'todo'

// Connects the application to MongoDB using the connection string
MongoClient.connect(dbConnectionStr, { useUnifiedTopology: true })
.then(client => {
// Displays a message when the database connection is successful
console.log(`Connected to ${dbName} Database`)

// Selects the todo database
db = client.db(dbName)
})


// Sets EJS as the view engine for rendering HTML pages
app.set('view engine', 'ejs')

// Serves static files such as CSS and JavaScript from the public folder
app.use(express.static('public'))

// Allows the server to receive data from HTML forms
app.use(express.urlencoded({ extended: true }))

// Allows the server to receive JSON data
app.use(express.json())

// GET route for the home page
app.get('/', async (request, response) => {

app.get('/',async (request, response)=>{
// Gets all to-do items from the todos collection
const todoItems = await db.collection('todos').find().toArray()
const itemsLeft = await db.collection('todos').countDocuments({completed: false})

// Counts how many to-do items are not completed
const itemsLeft = await db.collection('todos').countDocuments({ completed: false })

// Renders the index.ejs page and sends the to-do items and count to it
response.render('index.ejs', { items: todoItems, left: itemsLeft })

// Older version of the code that used promises instead of async/await
// db.collection('todos').find().toArray()
// .then(data => {
// db.collection('todos').countDocuments({completed: false})
Expand All @@ -35,59 +64,105 @@ app.get('/',async (request, response)=>{
// .catch(error => console.error(error))
})

// POST route for adding a new to-do item
app.post('/addTodo', (request, response) => {
db.collection('todos').insertOne({thing: request.body.todoItem, completed: false})

// Adds the new to-do item to the todos collection
// New items start with completed set to false
db.collection('todos').insertOne({
thing: request.body.todoItem,
completed: false
})

.then(result => {
// Displays a message when the to-do item is added
console.log('Todo Added')

// Redirects the user back to the home page
response.redirect('/')
})

.catch(error => console.error(error))
})

// PUT route for marking a to-do item as complete
app.put('/markComplete', (request, response) => {
db.collection('todos').updateOne({thing: request.body.itemFromJS},{
$set: {
completed: true
}
},{
sort: {_id: -1},
upsert: false
})

// Finds the selected to-do item and changes completed to true
db.collection('todos').updateOne(
{ thing: request.body.itemFromJS },
{
$set: {
completed: true
}
},
{
sort: { _id: -1 },
upsert: false
}
)

.then(result => {
// Displays a message when the item is marked complete
console.log('Marked Complete')

// Sends a response back to the JavaScript in the browser
response.json('Marked Complete')
})
.catch(error => console.error(error))

.catch(error => console.error(error))
})

// PUT route for marking a completed to-do item as incomplete
app.put('/markUnComplete', (request, response) => {
db.collection('todos').updateOne({thing: request.body.itemFromJS},{
$set: {
completed: false
}
},{
sort: {_id: -1},
upsert: false
})

// Finds the selected to-do item and changes completed back to false
db.collection('todos').updateOne(
{ thing: request.body.itemFromJS },
{
$set: {
completed: false
}
},
{
sort: { _id: -1 },
upsert: false
}
)

.then(result => {
// Displays a message when the item is marked incomplete
console.log('Marked Complete')

// Sends a response back to the JavaScript in the browser
response.json('Marked Complete')
})
.catch(error => console.error(error))

.catch(error => console.error(error))
})

// DELETE route for deleting a to-do item
app.delete('/deleteItem', (request, response) => {
db.collection('todos').deleteOne({thing: request.body.itemFromJS})

// Finds and deletes the selected to-do item
db.collection('todos').deleteOne({
thing: request.body.itemFromJS
})

.then(result => {
// Displays a message when the item is deleted
console.log('Todo Deleted')

// Sends a response back to the JavaScript in the browser
response.json('Todo Deleted')
})
.catch(error => console.error(error))

.catch(error => console.error(error))
})

app.listen(process.env.PORT || PORT, ()=>{
// Starts the Express server
app.listen(process.env.PORT || PORT, () => {

// Displays the port where the server is running
console.log(`Server running on port ${PORT}`)
})
})
11 changes: 11 additions & 0 deletions views/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,25 @@
<% } %>
</ul>

<!-- Displays the number of to-do items that are still incomplete -->
<h2>Left to do: <%= left %></h2>

<!-- Displays a heading for adding a new to-do item -->
<h2>Add A Todo:</h2>



<!-- Creates a form that sends the new to-do item to the server -->
<form action="/addTodo" method="POST">
<!-- Creates a text box where the user can type a new to-do item -->
<input type="text" placeholder="Thing To Do" name="todoItem">
<!-- Creates a button that submits the new to-do item -->
<input type="submit">
</form>






<script src='js/main.js'></script>
Expand Down