I have an Express server with a route for deleting a (psychology) experiment. (I have split my routes into multiple files. This route is in admin.js and thus its full route path is /admin/experiments/:expId)
router.route('/experiments/:expId')
.delete(tokens.verifyToken, adminValidator.isAdmin, (req, res) => {
const experimentId = req.params.expId;
const db = req.db;
db.removeExperiment(experimentId);
renderExperiments(req, res, db);
})
function renderExperiments(req, res, db) {
let allExps = expStandard.getAllExperiments(db);
res.render('adminExperiments', {
allExps: allExps,
approved_flag: APPROVED_EXPERIMENT,
pending_flag: PENDING_EXPERIMENT
});
}
This route deletes the experiment from the database and then calls a method which renders the associated adminExperiments.ejs view. This is an EJS template that simply creates an HTML table. Each row of the table corresponds to an experiment. And in each row I have included a delete button. Each delete button is associated with an EventListener for when the button is clicked:
A row from the table showing information about a given experiment
Here is the code in the associated js script (adminExperiments.js) which is executed on the client side:
document.addEventListener('DOMContentLoaded', registerDeleteExpListeners);
function registerDeleteExpListeners() {
let deleteButtons = document.querySelectorAll('.btn_exp_delete');
for (b of deleteButtons) {
b.addEventListener("click", deleteExperiment);
}
}
async function deleteExperiment(event) {
// ???
}
Question:
What do I use in the event listener deleteExperiment() to connect to my Express route?
I tried using Fetch with a method header of "delete" and sending it to the URL for the route (/admin/experiments/:expId). Although I can send a delete request to the route and it is received, it does not render adminExperiments.ejs. Instead, a response object is sent back with a status of 200. That’s great but it’s not what I want. I want a new page rendered with the updated list of experiments.
2
Answers
Apparently, this cannot be done with Fetch. Fetch does exactly what it says: it fetches data. It does not redirect/render a new page.
To do so, I included this line of code after using fetch to make the delete request:
In other words, I had to manually point the window to a different URL.
Well, yes, since a fetch request does not alter the location of the user, but sends a request in the background.
@America Holloway’s answer is half correct. Be careful not to misunderstand fetch(), since it does not “fetch” data, but fetch a request. This request can retrieve data, update data, delete data, etc., it depends on the request, its method and what the server that receives the request does with it.
And while
window.location.replace(...);
would indeed do the trick, do you really want the user to reload the page every time an experiment is deleted? You even say that with a delete fetch request the route is called, hopefully also deletes the item in the db, but only responds with a status of 200. This just means everything went ok, and you can then work from there.There are multiple ways to go from here. First, you would not need to send back the whole rendered page, but instead just something simple like
res.json({success: true})
or anything else that lets you distinguish on the client-side if the request succeeded or not.From there, on the client-side, you need to react to the response of the request. There are far too many ways to go about this, but here are some examples of what I would do:
since you are using EJS, you could put the HTML of the table in a new file, e.g.
experiments-table.ejs
, put that in the page asFinally, change the route handler of
/admin/experiments/:expId
so that it just renders that partial again. On the client-side, you can then simply replace the table.something different, but simple, would be to delete that row on success. So either work with HTTP status codes and delete the row on status
200
, show error on status4xx
/5xx
, etc., or do something like aboveres.json({success: true})
and delete the row if it’s true.As said before, there are many many other ways to do this, it depends on how you want to do it. You had it already right with the fetch request, all you need to implement is what happens after the response.