bertmi01's avatar

Help with drag and dropped file missing from request

I've been trying to make my own drag and drop file upload component and it works absolutely fine when I click to upload a file through the file select dialogue, but no luck with the drag and drop.

I've been using these articles as a guide: https://www.raymondcamden.com/2019/08/08/drag-and-drop-file-upload-in-vuejs https://dev.to/hundredrab/yet-another-vue-drag-and-drop-15m2

One thing is that if I log the file object to the console through either method, they're virtually the same so I'm not sure why the dropped file doesn't show up in the request.

<template>
<div v-cloak @drop.prevent @dragover.prevent>

    <h1>Upload {{documentName}} <span>{{restriction}}</span></h1>

    <div v-if="documentLocation">
      <div>
        <a :href="'/download/'+documentLocation">
          <b>{{documentName}}</b> uploaded on {{documentUploadDate}}
        </a>
        <button @click="deleteDocument" type="button" role="button">
          delete
        </button>
      </div>
    </div>

    <div v-if="file">
      <div>
        <div>
          <b>{{ file.name }} ({{ formatBytes(file.size) }})</b>
          
          <button @click="file = null">
            remove
          </button>
        </div>
      </div>
    </div>

    <div v-show="!file && documentLocation == null" @drop="dropFile">
      <div>
  
        <button type="button"  @click="upload">
          click here or drag and drop your file
        </button>

        <input type="file" :name="uploadName" :id="uploadName" style="display: none" @change="handleFile">
        <input type="hidden" :name="'delete_'+uploadName" v-if="deleteToggle">

      </div>
    </div>
  </div>
</template>

Script:

<script>
export default {
  name: 'file-upload-bucket',

  props: {
    uploadName: { type: String, default: 'testUpload' },
    documentName: { type: String, default: null },
    documentLocationProp: { type: String, default: null },
    documentUploadDate: {},
    restriction: { type: String, default: null }
  },

  data() {
    return {
      file: null,
      documentLocation: null,
      deleteToggle: false,
    }
  },

  mounted: function() {
    if(this.documentLocationProp) {this.documentLocation = this.documentLocationProp;}
  },

  methods: {

    upload() { document.getElementById(this.uploadName).click(); },

    handleFile(e) {
      let file = e.target.files[0];
      if (!file) return;
      this.file = file;
      this.deleteToggle = false;
    },

    dropFile(e) {
      let droppedFile = e.dataTransfer.files[0];
      if (!droppedFile) return;
      this.file = droppedFile;
      this.deleteToggle = false;
    },

    formatBytes(a,b){if(0==a)return"0 Bytes";var c=1024,d=b||2,e=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],f=Math.floor(Math.log(a)/Math.log(c));return parseFloat((a/Math.pow(c,f)).toFixed(d))+" "+e[f]},

    deleteDocument() {
      if (window.confirm('Really delete '+this.documentName+'?')) { this.documentLocation = null; this.deleteToggle = true; }
    }
  },


}
</script>

Any help would be sincerely appreciated!

0 likes
3 replies
bertmi01's avatar

#2, the file input isn't passed along in the request. If I select a file by clicking and using the browser's file select dialogue, it makes it along to the request just fine. Please let me know if I can provide more information.

bertmi01's avatar
bertmi01
OP
Best Answer
Level 3

So, I solved my problem. in case anyone is searching for a similar solution. I set the ref on the input and pass $refs.file to my handleFile function. Then I modified dropFile to set this.$refs.file.files to e.dataTransfer.files, and pass that ref to handleFile, so I suppose that forces the dragged file to be interpreted by the DOM in the same way? I honestly don't understand, but this works.

Hope it helps someone!

<input type="file" :name="uploadName" :id="uploadName" style="display: none" ref="file" @change="handleFile($refs.file)">
    handleFile(ref) {
      let file = ref.files[0];
      if (!file) return;
      this.file = file;
      this.deleteToggle = false;
    },

    dropFile(e) {
      this.$refs.file.files = e.dataTransfer.files;
      this.handleFile(this.$refs.file);
    },

Please or to participate in this conversation.