Update and Delete With Express




Lesson Objectives

  1. Create a Delete Route
  2. Make the index page send a DELETE request
  3. Create an edit route
  4. Create a link to the edit route
  5. Create an update route
  6. Make the edit page send a PUT request



Delete




Create a Delete Route

Inside our server.js file, add a DELETE route:

app.delete('/fruits/:indexOfFruitsArray', (req, res) => {
	fruits.splice(req.params.indexOfFruitsArray, 1); //remove the item from the array
	res.redirect('/fruits');  //redirect back to index route
});



Test it using:

curl -X DELETE localhost:3000/fruits/1



Make the index page send a DELETE request

Inside our index.ejs file, add a form with just a delete button.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Fruits App</title>
        <link rel="stylesheet" href="/css/app.css">
    </head>
    <body>
        <h1>Fruits index page</h1>
        <ul>
            <% for(let i = 0; i < fruits.length; i++){ %>
                <li>
			The <a href="/fruits/<%=i%>"><%=fruits[i].name; %></a> is  <%=fruits[i].color; %>.
			<!--  ADD DELETE FORM HERE-->
			<form>
				<input type="submit" value="DELETE"/>
			</form>
                </li>
            <% } %>
        </ul>
        <nav>
            <a href="/fruits/new">Create a New Fruit</a>
        </nav>
    </body>
</html>



When we click "DELETE" on our index page (index.ejs), the form needs to make a DELETE request to our DELETE route.

The problem is that forms can't make DELETE requests. Only POST and GET. We can fake this, though. First we need to install an npm package called method-override

npm install method-override



Now, in our server.js file, add:

//include the method-override package
const methodOverride = require('method-override');
//...
//after app has been defined
//use methodOverride.  We'll be adding a query parameter to our delete form named _method
app.use(methodOverride('_method'));



Now go back and set up our delete form to send a DELETE request to the appropriate route

<form action="/fruits/<%=i; %>?_method=DELETE" method="POST">



Update




Create an edit route

In our server.js, create a GET route which will just display an edit form for a single todo item.

app.get('/fruits/:indexOfFruitsArray/edit', (req, res) => {
	res.render(
		'edit.ejs', //render views/edit.ejs
		{ //pass in an object that contains
			fruit: fruits[req.params.indexOfFruitsArray], //the fruit object
			index: req.params.indexOfFruitsArray //... and its index in the array
		}
	);
});



Now create a very basic form for editing in views/edit.ejs

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Fruits App</title>
        <link rel="stylesheet" href="/css/app.css">
    </head>
    <body>
        <h1>Edit Fruit Page</h1>
        <form>
		<!--  NOTE: the form is pre-populated with values for the server-->
		Name: <input type="text" name="name" value="<%=fruit.name%>"/><br/>
		Color: <input type="text" name="color" value="<%=fruit.color%>"/><br/>
		Is Ready To Eat:
		<input type="checkbox" name="readyToEat"
		    <% if(fruit.readyToEat === true){ %>
			checked
		    <% } %>
		/>
		<br/>
		<input type="submit" name="" value="Submit Changes"/>
        </form>
    </body>
</html>



Inside our index.ejs file, add a link to our edit route which passes in the index of that item in the url

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Fruits App</title>
        <link rel="stylesheet" href="/css/app.css">
    </head>
    <body>
        <h1>Fruits index page</h1>
        <ul>
            <% for(var i = 0; i < fruits.length; i++){ %>
                <li>
			The <a href="/fruits/<%=i%>"><%=fruits[i].name; %></a> is  <%=fruits[i].color; %>.
			<% if(fruits[i].readyToEat === true){ %>
				It is ready to eat
			<% } else { %>
				It is not ready to eat
			<% } %>
			<form action="/fruits/<%=i; %>?_method=DELETE" method="POST">
				<input type="submit" value="DELETE"/>
			</form>
			<!-- Add edit link here  -->
			<a href="/fruits/<%=i; %>/edit">Edit</a>
		</li>
            <% } %>
        </ul>
        <nav>
            <a href="/fruits/new">Create a New Fruit</a>
        </nav>
    </body>
</html>



Create an update route

In order to UPDATE, we use the http verb PUT.

Inside server.js add the following:

app.put('/fruits/:indexOfFruitsArray', (req, res) => { //:indexOfFruitsArray is the index of our fruits array that we want to change
	if(req.body.readyToEat === 'on') { //if checked, req.body.readyToEat is set to 'on'
		req.body.readyToEat = true;
	} else { //if not checked, req.body.readyToEat is undefined
		req.body.readyToEat = false;
	}
	fruits[req.params.indexOfFruitsArray] = req.body; //in our fruits array, find the index that is specified in the url (:indexOfFruitsArray).  Set that element to the value of req.body (the input data)
	res.redirect('/fruits'); //redirect to the index page
});



Make the edit page send a PUT request

When we click "Submit Changes" on our edit page (edit.ejs), the form needs to make a PUT request to our update route

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Fruits App</title>
        <link rel="stylesheet" href="/css/app.css">
    </head>
    <body>
        <h1>Edit Fruit Page</h1>
	<!--  ADD action attribute to form tag-->
        <form action="/fruits/<%=index%>">
		Name: <input type="text" name="name" value="<%=fruit.name%>"/><br/>
		Color: <input type="text" name="color" value="<%=fruit.color%>"/><br/>
		Is Ready To Eat:
		<input type="checkbox" name="readyToEat"
			<% if(fruit.readyToEat === true){ %>
				checked
			<% } %>
		/>
		<br/>
		<input type="submit" name="" value="Submit Changes"/>
        </form>
    </body>
</html>



The problem is that forms can't make PUT requests. Only POST and GET. We can fake this, though with method override:

<form action="/fruits/<%=index%>?_method=PUT" method="POST">



References