I have some JavaScript that previews image thumbnails prior to form submission, where the thumbnails/files can be deleted by the user prior to form submission.
Due to problems/a bug in Safari around the FileList property on input elements, I've had to create an array of the files where the images are pushed into the array or spliced out if removed before submission.
The server side code is handled with PHP and the filenames are uploaded to a MySQL database.
Using other questions/answers on this site, the JavaScript below has solved the issues with the bug in Safari, but the form isn't actually submitting? I think by problem is in the last part of the code around the FormData object? I'm wondering if I should be using the set() method not append on the FormData object? I seem to have hit a wall.
I know the PHP / MySQL code is all working OK because if I use the original code that doesn't work properly in Safari the PHP all submits OK in Chrome and the database is updated correctly.
Any help / advice on how to solve it would be amazing.
Codepen: https://codepen.io/anna_paul/pen/KKZERrV
Note: using JSON URL endpoints is not an option.
// an Array to hold our files, accessible to all of the functions below
const files = [];
// HTML elements
var dropZone = document.getElementById("drop-zone"),
showSelectedImages = document.getElementById("show-selected-images"),
fileUploader = document.getElementById("standard-upload-files");
dropZone.addEventListener("click", (evt) => {
// assigns the dropzone to the hidden input element so when you click 'select files' it brings up a file picker window
fileUploader.click();
});
// Prevent browser default when dragginf files over the drop zone
dropZone.addEventListener("dragover", (evt) => {
evt.preventDefault();
});
fileUploader.addEventListener("change", (evt) => {
files.push(...fileUploader.files);
[...fileUploader.files].forEach(updateThumbnail);
console.log(fileUploader.files)
});
dropZone.addEventListener("drop", (evt) => {
evt.preventDefault();
const dropped_files = evt.dataTransfer.files;
if (dropped_files.length) {
files.push(...dropped_files);
}
[...dropped_files].forEach(updateThumbnail);
});
// updateThumbnail function that needs to be able to handle multiple files
function updateThumbnail(file) {
if (file.type.startsWith("image/")) {
// create elements to hold the image preview thumbnail
let uploadImageWrapper = document.createElement("figure"),
removeImage = document.createElement("div"),
thumbnailElement = new Image();
// 'x' that deletes the image
removeImage.classList.add("remove-image");
removeImage.innerHTML =
'<svg width="10" height="10" viewBox="0 0 150 150"><path fill="#fff" d="M147.23,133.89a9.43,9.43,0,1,1-13.33,13.34L75,88.34,16.1,147.23A9.43,9.43,0,1,1,2.76,133.89L61.66,75,2.76,16.09A9.43,9.43,0,0,1,16.1,2.77L75,61.66,133.9,2.77a9.42,9.42,0,1,1,13.33,13.32L88.33,75Z"/></svg>';
// image thumbnail
thumbnailElement.classList.add("drop-zone__thumb");
thumbnailElement.src = URL.createObjectURL(file);
// revoke the blob:// URL when the image is loaded
thumbnailElement.onload = (evt) => URL.revokeObjectURL(thumbnailElement.src);
// appending elements
showSelectedImages.append(uploadImageWrapper); // <figure> element
uploadImageWrapper.append(removeImage); // 'x' to delete
uploadImageWrapper.append(thumbnailElement); // image thumbnail
// Delete images
removeImage.addEventListener("click", (evt) => {
const deleteImage = removeImage.parentElement;
deleteImage.remove();
const index = files.indexOf(file);
files.splice(index, 1);
});
}
} // end of 'updateThumbnail' function
// HANDLE UPLOAD TO SERVER
document.getElementById("upload-images-form").onsubmit = (evt) => {
evt.preventDefault();
console.log("uploading", files.slice());
const formdata = new FormData();
for (const file of files) {
formdata.append("submit-images", file);
}
// URL details
var myURL = new URL(window.location.href),
pagePath = myURL.pathname
fetch ( pagePath, {
method: "POST",
body: formdata
})
.then(resp => resp.text())
// .then(console.log)
.catch(console.error)
}
console.log(fileUploader.files)
body {
margin: 0;
display: flex;
justify-content: center;
width: 100%;
}
form {
width: 30%;
}
#drop-zone {
border: 1px dashed;
width: 100%;
padding: 1rem;
margin-bottom: 1rem;
}
.select-files {
text-decoration: underline;
cursor: pointer;
}
/* images that are previewed prior to form submission*/
.drop-zone__thumb {
width: 200px;
height: auto;
display: block;
}
#remove-x {
width: 1rem;
height: 1rem;
}
#submit-images {
margin: 1rem 0;
}
#show-selected-images {
display: flex;
}
<form id="upload-images-form" enctype="multipart/form-data" method="post">
<h1>Upload Your Images</h1>
<div id="drop-zone" class="drop-zone flex">
<p>DRAG AND DROP IMAGES HERE</p>
<p>Or</p>
<p class="select-files">Select Files</p>
</div>
<input id="standard-upload-files" style="display:none" style="min-width: 100%" type="file" name="standard-upload-files[]" multiple>
<input type="submit" name="submit-images" id="submit-images" value="SUBMIT IMAGES">
<div id="show-selected-images"></div>
</form>