Skip to content

Instantly share code, notes, and snippets.

@tjkhara
Last active July 27, 2022 11:51
Show Gist options
  • Select an option

  • Save tjkhara/4cba683a1e91e995c495fbd36cf0aea0 to your computer and use it in GitHub Desktop.

Select an option

Save tjkhara/4cba683a1e91e995c495fbd36cf0aea0 to your computer and use it in GitHub Desktop.
Creating a new item without page reload

Creating a new item without page reload

Intercept default behavior of submitting a form

Go to server.js and first add some ids:

let express = require('express')
let mongodb = require('mongodb') // Import mongodb package

let app = express()

// Create db connection
let db

// How to server static existing files
// This makes the contents of this folder available from the root of the server
app.use(express.static('public'))

// Connection string
let connectionString = 'mongodb+srv://todoappuser:[email protected]/TodoApp?retryWrites=true&w=majority'

mongodb.connect(connectionString, {useNewUrlParser: true}, function(err, client){
	// This function is called after the connection is established
	db = client.db() // This selects the mongodb database
	// Only start listening to requests once the db connection is ready
	app.listen(3000)
})

// Take form data and add it to the body object that lives on the request object (req.body)
// This is the same thing as the line below, but for asynchrnous requests
app.use(express.json())




// Add all form values to the body object
// and add that to the request object
// makes it easy to access the form data
// Take form data and add it to the body object that lives on the request object (req.body)
app.use(express.urlencoded({extended: false}))


app.get('/', function (req, res) {

	// First read the data from the database
	// find any and all documents and convert to array
	db.collection('items').find().toArray(function(err, items){

		// We want to send back the response once the db action is complete
		res.send(`

		<!DOCTYPE html>
		<html>
		<head>
			<meta charset="UTF-8">
			<meta name="viewport" content="width=device-width, initial-scale=1.0">
			<title>Simple To-Do App</title>
			<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity_no="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
		</head>
		<body>
			<div class="container">
				<h1 class="display-4 text-center py-1">To-Do App!</h1>

				<div class="jumbotron p-3 shadow-sm">
					<form id="create-form" action="/create-item" method="POST">
						<div class="d-flex align-items-center">
							<input id="create-field" name="item" autofocus autocomplete="off" class="form-control mr-3" type="text" style="flex: 1;">
							<button class="btn btn-primary">Add New Item</button>
						</div>
					</form>
				</div>

				<ul id="item-list" class="list-group pb-5">
					${items.map(function(item){
						return `<li class="list-group-item list-group-item-action d-flex align-items-center justify-content-between">
										<span class="item-text">${item.text}</span>
										<div>
										<button data-id="${item._id}" class="edit-me btn btn-secondary btn-sm mr-1">Edit</button>
										<button data-id="${item._id}" class="delete-me btn btn-danger btn-sm">Delete</button>
										</div>
										</li>`
					}).join('')}
				</ul>

			</div>

			<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
			<script src="/browser.js">

			</script>
		</body>
		</html>

	`)
	}) 
})


app.post('/create-item', function(req, res){
	// log out to the console the value that the user typed in
	// console.log(req.body.item)

	// Create new document in the mongodb database
	db.collection('items').insertOne({text: req.body.item}, function(){
		res.redirect('/')
	})
})


app.post('/update-item', function(req, res){
	// This was for initial test
	// console.log(req.body.text)
	// res.send("Success")

	db.collection('items').findOneAndUpdate({_id: new mongodb.ObjectID(req.body.id)}, {$set: {text: req.body.text}}, function(){
		res.send(`Success`)
	})
})

app.post('/delete-item', function(req, res){
	// Perform CRUD
	db.collection('items').deleteOne({_id: new mongodb.ObjectID(req.body.id)}, function(){
		res.send("Success")
	})
})

Go back to browser.js

// Create feature
document.getElementById("create-form").addEventListener(a, b)

a is the event we are looking out for

// Create feature

let createField = document.getElementById("create-field")

document.getElementById("create-form").addEventListener("submit", function(e){
	e.preventDefault()
	// Extract value and send to axios
	axios.post('/create-item', {text: createField.value}).then(function(){
		// Create the HTML for a new item
		alert("You've just created a new item")

	}).catch(function(){
		console.log("Please try again later")
	})

Go back to server.js

Modify this function

app.post('/create-item', function(req, res){
	// log out to the console the value that the user typed in
	// console.log(req.body.item)

	// Create new document in the mongodb database
	db.collection('items').insertOne({text: req.body.text}, function(){
		res.send("Success")
	})
})

})

At this point if we submit a value to the create item it puts it in the database.

Now we go to browser.js and take care of adding the html from the new item

// Create feature

let createField = document.getElementById("create-field")

document.getElementById("create-form").addEventListener("submit", function(e){
  e.preventDefault()
  // Extract value and send to axios
  axios.post('/create-item', {text: createField.value}).then(function(){
    // Create the HTML for a new item
    alert("You've just created a new item")

  }).catch(function(){
    console.log("Please try again later")
  })

})

Add this line

document.getElementById("item-list").insertAdjacentHTML(a, b)

a is where you want to add the html b is the HTML we want to add

This is the completed code

Using the li item from the server.js

function itemTemplate(item){
  return `<li class="list-group-item list-group-item-action d-flex align-items-center justify-content-between">
	  <span class="item-text">${item.text}</span>
	  <div>
	  <button data-id="${item._id}" class="edit-me btn btn-secondary btn-sm mr-1">Edit</button>
	  <button data-id="${item._id}" class="delete-me btn btn-danger btn-sm">Delete</button>
	  </div>
	  </li>`
}

// Create feature

let createField = document.getElementById("create-field")

document.getElementById("create-form").addEventListener("submit", function(e){
  e.preventDefault()
  // Extract value and send to axios
  axios.post('/create-item', {text: createField.value}).then(function(response){
    // Create the HTML for a new item
    document.getElementById("item-list").insertAdjacentHTML("beforeend", itemTemplate(response.data))

  }).catch(function(){
    console.log("Please try again later")
  })

})

Note the response and response.data in this line

axios.post('/create-item', {text: createField.value}).then(function(response){
    // Create the HTML for a new item
    document.getElementById("item-list").insertAdjacentHTML("beforeend", itemTemplate(response.data))

In the server.js we modified this function to send back the response that contains some text

app.post('/create-item', function(req, res){
  // log out to the console the value that the user typed in
  // console.log(req.body.item)

  // Create new document in the mongodb database
  db.collection('items').insertOne({text: req.body.text}, function(err, info){
    res.json(info.ops[0])
  })
})

Imporving user experience - clear field after the value is entered

Finished function

Added these two lines:

createField.value = ""
    createField.focus()

function itemTemplate(item){
  return `<li class="list-group-item list-group-item-action d-flex align-items-center justify-content-between">
	  <span class="item-text">${item.text}</span>
	  <div>
	  <button data-id="${item._id}" class="edit-me btn btn-secondary btn-sm mr-1">Edit</button>
	  <button data-id="${item._id}" class="delete-me btn btn-danger btn-sm">Delete</button>
	  </div>
	  </li>`
}

// Create feature

let createField = document.getElementById("create-field")

document.getElementById("create-form").addEventListener("submit", function(e){
  e.preventDefault()
  // Extract value and send to axios
  axios.post('/create-item', {text: createField.value}).then(function(response){
    // Create the HTML for a new item
    document.getElementById("item-list").insertAdjacentHTML("beforeend", itemTemplate(response.data))
    createField.value = ""
    createField.focus()

  }).catch(function(){
    console.log("Please try again later")
  })

})
@PoornachandraSK
Copy link

Error: res.json(info.ops[0])

TypeError: Cannot read properties of undefined (reading '0')
at C:\Users\ACER\Desktop\Todoapp\server.js:68:26
at C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\utils.js:425:9
at C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\operations\execute_operation.js:71:66
at C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\utils.js:425:9
at completeEndSession (C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\sessions.js:154:17)
at C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\sessions.js:166:13
at maybePromise (C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\utils.js:411:5)
at ClientSession.endSession (C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\sessions.js:133:41)
at C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\operations\execute_operation.js:71:36
at C:\Users\ACER\Desktop\Todoapp\node_modules\mongodb\lib\operations\execute_operation.js:178:21
[nodemon] app crashed - waiting for file changes before starting...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment