The Context
I have a form that contains image components which are outputted via a MySQL database with PHP. I have some javascript fetch()
functionality on different pages of the site to make the user experience better, but in these instances the functionality relates to functionality of the individual forms. In the instance below I have multiple components inside a single <form>
instance.
The components are outputted with a while
loop inside the form (it is done in this manner so that multiple images can be uploaded on a single form submission).
The Problem
I would like to use the javascript fetch()
functionality when an image (i.e. image component) is deleted, in other words, have the component deleted without the page doing a hard refresh.
I’ve included an amended version of the javascript that worked when I initially had each image inside its own form (not a practical user experience in reality). I thought if I was selecting the image component inside the form i.e. the .upload-details-component
with a forEach
loop this would work? I can’t get this to work though.
Here is a screenshot of the grid itself. The ‘delete’ word is the delete button:
[![enter image description here][1]][1]HTML
<form class="upload-details-form upload-form-js" method="post" enctype="multipart/form-data">
<div class="image-component-wrapper">
<!-- image-component-wrapper start -->
<?php
$user_id = $db_id; // database id imported from header.php
$stmt = $connection->prepare("SELECT * FROM lj_imageposts WHERE user_id = :user_id"); $stmt->execute([ ':user_id' => $user_id ]); while ($row = $stmt->fetch()) { $db_image_id = htmlspecialchars($row['image_id']); ?>
<div class="upload-details-component">
<img src="image.jpg" />
<div class="form-row">
<input id="title-id-<?php echo $db_image_id; ?>" value="Image Title" type="text" name="image-title[]" placeholder="Image Title" />
</div>
<div class="form-row">
<!-- BUTTON THAT DELETES AND IMAGE -->
<button name="upload-details-delete" value="<?php echo $db_image_id; ?>" style="background: #cc1f1f;" class="remove-image">DELETE</button>
<input type="hidden" name="image-id[]" value="<?php echo $db_image_id; ?>" />
</div>
</div>
<?php } ?>
</div>
<!-- image-component-wrapper end -->
<div class="form-row">
<button id="upload-submit" type="submit" name="upload-submit">COMPLETE UPLOADS</button>
</div>
</form>
JAVASCRIPT
// ---- FETCH
var forms = document.querySelectorAll(".upload-form-js"),
// image component
uploadDetailsComponent = document.querySelectorAll(".upload-details-component"),
// delete button
deleteButton = document.querySelectorAll(".remove-image");
// URL details
var myURL = new URL(window.location.href),
pagePath = myURL.pathname;
if (uploadDetailsComponent) {
uploadDetailsComponent.forEach((item) => {
deleteButton.forEach((button) => {
button.addEventListener("click", (e) => (item._button = button)); //store this button in the form element
});
item.addEventListener("submit", function (evt, btn) {
evt.preventDefault();
var formData = new FormData(this);
if (this._button) {
// submitted by a button?
formData.set(this._button.name, this._button.value);
// delete this._button; //this only needed if form can be submitted without submit button (aka submitted by javascript)
}
fetch(pagePath, {
method: "post",
body: formData,
})
.then(function (response) {
return response.text();
// }).then(function(data){
// console.log(data);
})
.catch(function (error) {
console.error(error);
});
item.remove(); // removes component from HTML
});
});
} // end of if (upload-details-component)
3
Answers
So what you can do is pass the ‘event’ object, or ‘e’, when a user submits the form.
You can then use e.preventDefault() to stop the form from doing it’s default behaviour of submitting the form and then refreshing the page
It’s a very common thing to do in React with from submissions
What you can then do is have a function run in the background that does the fetch function that makes the HTTP DELETE request. On the frontend, you can then delete the HTML node that contains the image you want to delete.
Just make sure you wait for the response of your fetch, using asycn/await, to determine if you should delete the HTML node from the DOM
Instead of doing this:
Rather do it so:
I made an event listener on the form. If one of the "delete image" buttons are clicked, I call the
deleteImage()
function with the id. In any other case (clicking on the submit button) the form will do an old school POST request.The
deleteImage()
function will do a fetch request. Here I use a fake data URL to make the example run here on ST. The URL should of course be your real URL endpoint for deleting. In the call back function (the lastthen()
) I find the component with the right id and delete the component from the UI.If your desired outcome is to have the form data submitted/saved when the delete button is clicked under an image (i.e. the same behaviour as submitting the form), then the following code should achieve close to what you want.
When a user clicks delete, it will:
fetch