Skip to content Skip to sidebar Skip to footer

Delete An Image() Object From Memory On Click Event Of Sibling Element — JavaScript

I have an image previewer that uses the JavaScript Image() object to preview images prior to them being processed with PHP. I have a div that contains an 'x' SVG graphic that is ta

Solution 1:

Problem:

You are not updating fileUploader.files when you add/remove an item.

Solution

Every time you drop/remove a file you need to update the fileUploader input. The first step is to create a function to handle the FileList object and change only two lines of your code:

//--> to create a FileList
function getFileListItems (files) {
  var transferObject = new ClipboardEvent("").clipboardData || new DataTransfer()
  for (var i = 0; i<files.length; i++) transferObject.items.add(files[i])
  return transferObject.files;
}

 

Add files during the drop event:

 //--> Updating files during drop event
 fileUploader.files = getFileListItems([...fileUploader.files, ...evt.dataTransfer.files]);

Removing a file:

fileUploader.files = getFileListItems([...fileUploader.files].filter(f => file!==f));

See a complete working example:

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

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

function getFileListItems(files) {
  var transferObject = new ClipboardEvent("").clipboardData || new DataTransfer()
  for (var i = 0; i < files.length; i++) transferObject.items.add(files[i])
  return transferObject.files;
}

dropZone.addEventListener("drop", (evt) => {
  evt.preventDefault();
  // assign dropped files to the hidden input element
  if (evt.dataTransfer.files.length) {
    fileUploader.files = getFileListItems([...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/")) {
    let uploadImageWrapper = document.createElement("article"),
      removeImage = document.createElement("div"),
      thumbnailElement = new Image();

    // 'x' that deletes the image
    removeImage.classList.add("remove-image");
    removeImage.innerHTML =
      '<svg id="remove-x" viewBox="0 0 150 150"><path fill="#000" 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);

    // appending elements
    showSelectedImages.append(uploadImageWrapper); // <article> element
    uploadImageWrapper.append(removeImage); // 'x' to delete
    uploadImageWrapper.append(thumbnailElement); // image thumbnail

    // Delete images
    removeImage.addEventListener("click", (evt) => {
      if (evt.target) {
        var deleteImage = removeImage.parentElement;
        deleteImage.remove();
        fileUploader.files = getFileListItems([...fileUploader.files].filter(f => file !== f));
      }
    });
  }
} // 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 preview prior to form submit*/

.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 class="td text-center">DRAG AND DROP IMAGES HERE</p>
    <p class="td text-center" style="margin: 0">Or</p>
    <p class="tl text-center select-files text-bold pointer">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>

Working example


Solution 2:

This is because when a form submitted, it doesn't submit every HTML element in the form, but only values of input, textarea, pressed button and some others that have name attribute.

So what you need is clear the file input field too:

const showSelectedImages = document.getElementById("preview");
const input = document.getElementById("test");

function updateThumbnail(file) {
  if (file.type.startsWith("image/")) {

    // image and 'x' to delete wrapper 
    const uploadImageWrapper = document.createElement('article')

    // div that holds the 'x' to delete
    const removeImage = document.createElement('div')

    // image preview element
    thumbnailElement = new Image()

    // 'x' that deletes the image
    removeImage.classList.add("remove-image")
    removeImage.innerHTML = 'x'

    // image thumbnail
    thumbnailElement.classList.add("drop-zone__thumb")
    thumbnailElement.src = URL.createObjectURL(file)

    // appending elements
    showSelectedImages.append(uploadImageWrapper) // <article> element
    uploadImageWrapper.append(removeImage) // 'x' to delete
    uploadImageWrapper.append(thumbnailElement) // image thumbnail

    // Delete Images when the 'x' div is clicked
    removeImage.addEventListener('click', (evt) => {
      if (evt.target) {
        var deleteImage = removeImage.parentElement
        deleteImage.remove();

        /* for single file input is enough clear value property */

        //        input.value = null;

        /* for multiple files input we'll need recreate new files list excluding deleted file */
        const dt = new DataTransfer();
        for (let f of input.files) {
          if (f !== file)
            dt.items.add(f);
        }

        input.files = dt.files;
      }
    })
  }

}

function updateThumbnails(files) {
  showSelectedImages.innerHTML = ""; //remove all previous previews
  for (let f of files)
    updateThumbnail(f);
}

function showform(form) {
  const list = {};
  for (let i of [...new FormData(form).entries()]) {
    const key = i[0].match(/^([^\[]+)\[\]$/);
    if (key) {
      if (!list[key[1]])
        list[key[1]] = [];
      list[key[1]][list[key[1]].length] = i[1];
    } else
      list[i[0]] = i[1];
  }
  console.log(list)
  return false;
}
.remove-image {
  cursor: pointer;
}

article {
  display: inline-block;
}
<form type="post" onsubmit="return showform(this);">
  <input type="hidden" name="myHiddenInput" value="blah">
  <input type="file" name="test[]" id="test" oninput="updateThumbnails(this.files)" multiple>
  <span id="preview"></span>
  <button type="submit">submit</button>
</form>

Post a Comment for "Delete An Image() Object From Memory On Click Event Of Sibling Element — JavaScript"