pjk_ok
pjk_ok

Reputation: 967

File Upload Form Not Working When Image Preview Wrapper Is Moved

I have a file uploader that handles multiple files which all works as intended.

The previews of the files to be uploaded are place inside a container in the upload form. When I move this element to a different part of the form (or outside of the form) the uploader doesn't work? I would ideally like the preview container that holds the images to be below the submit button (either inside or outside of the form).

I cannot for the life of me work out why this is happening. The element itself is empty prior to the image previews populating it, and I don't think the issue is being caused by the javascript (although happy to take guidance on this).

The element in question is this one:

<div id="show-selected-images"></div>

It currently sits in the middle of the form between the drop zone and the (hidden) file input element and a visible submit button, but as mentioned I would like to move it below the submit button.

NOTE: I've included the JS so the uploader works, but I suspect the JS may not be the issue.

Codepen: https://codepen.io/pauljohnknight/pen/xxdrvmR

// Query all needed elements in one go
const [dropZone, showSelectedImages, fileUploader] = document.querySelectorAll(
  "#standard-upload-files, #drop-zone, #show-selected-images"
);

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 draging over
dropZone.addEventListener("dragover", (evt) => {
  evt.preventDefault();
});

fileUploader.addEventListener("change", (evt) => {
  // Clear the already selected images
  showSelectedImages.innerHTML = "";
  // this function is further down but declared here and shows a thumbnail of the image
  [...fileUploader.files].forEach(updateThumbnail);
});

dropZone.addEventListener("drop", (evt) => {
  evt.preventDefault();
  // Clear the already selected images
  showSelectedImages.innerHTML = "";

  // assign dropped files to the hidden input element
  if (evt.dataTransfer.files.length) {
    fileUploader.files = evt.dataTransfer.files;
  }

  // function is declared here but written further down
  [...evt.dataTransfer.files].forEach(updateThumbnail);
});

// updateThumbnail function that needs to be able to handle multiple files
function updateThumbnail(file) {
  if (file.type.startsWith("image/")) {
    const thumbnailElement = new Image();
    thumbnailElement.classList.add("drop-zone__thumb");
    thumbnailElement.src = URL.createObjectURL(file);
    showSelectedImages.append(thumbnailElement);
  }
} // end of 'updateThumbnail' function
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;
}

/* image that is previewed prior to form submission*/
.drop-zone__thumb {
  width: 200px;
  height: auto;
  display: block;
}

#submit-images {
  margin-top: 1rem;
}
<form id="upload-images-form" enctype="multipart/form-data" method="post">
  <h1>Upload Your Images</h1>
  <div id="drop-zone" class="drop-zone">
    <p class="td text-center">DRAG AND DROP IMAGES HERE</p>
    <p>Or</p>
    <p class="select-files">Select Files</p>
  </div>
  <!-- below is the element that has the issue when moved -->
  <div id="show-selected-images"></div>
  <div class="inner-input-wrapper">
    <div class="upload-label-wrapper">
      <input id="standard-upload-files" style="display:none" type="file" name="standard-upload-files[]" multiple>
    </div>
    <input type="submit" name="submit-images" id="submit-images" value="SUBMIT IMAGES">
  </div>
</form>

Upvotes: 0

Views: 280

Answers (1)

Danila
Danila

Reputation: 18526

I think this part causes the issue:

// Query all needed elements in one go
const [dropZone, showSelectedImages, fileUploader] = document.querySelectorAll(
  "#standard-upload-files, #drop-zone, #show-selected-images"
);

It is very bad practice to query elements like that, because then you cannot change their order inside html without changing elements inside destructured array. In your case you are moving previews in the end and now your showSelectedImages variable is actually uploader and fileUploader is now div which holds previews, and everything messes up.

You need to query them one by one:

const fileUploader = document.getElementById('standard-upload-files');
const dropZone = document.getElementById('drop-zone');
const showSelectedImages = document.getElementById('show-selected-images');

Upvotes: 1

Related Questions