TransWikia.com

HTML drop zone file upload not working when dragging in files

Stack Overflow Asked on December 30, 2021

I have the following dropzone where users can either select images or drag images into the dropzone.
When I select files through the input type=file button and click the btnUpload button, the images are uploaded. However, when I drag items into the dropzone and then click btnUpload button, nothing happens: no logging, no network requests, nothing.
Why? Here’s my code.

<div id="drop-area">
<span id="status"></span>
<p>Drop files here</p>
<input type="file" id="fileElem" multiple accept="image/*" onchange="handleFiles(this.files)">
<label class="button" for="fileElem">Select files</label>
<progress id="progress-bar" max=100 value=0></progress>
<div id="gallery" /></div>
<input id="btnUpload" type="submit" class="button green small" value="Upload" />  


<script type="text/javascript">     
    let btnUpload = document.getElementById("btnUpload")
    btnUpload.addEventListener('click', uploadFiles, false)

    function uploadFiles(event) {
        event.preventDefault();
        // TODO - validate file size, extension & amount

        files = [...fileElem.files]
        // Submit each file separately.
        files.forEach(uploadFile)

        //check if success and if so, remove from gallery 
        

    }

    // This all copy & paste
    // ************************ Drag and drop ***************** //
    let dropArea = document.getElementById("drop-area")

        // Prevent default drag behaviors
        ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
            dropArea.addEventListener(eventName, preventDefaults, false)
            document.body.addEventListener(eventName, preventDefaults, false)
        })

        // Highlight drop area when item is dragged over it
        ;['dragenter', 'dragover'].forEach(eventName => {
            dropArea.addEventListener(eventName, highlight, false)
        })

        ;['dragleave', 'drop'].forEach(eventName => {
            dropArea.addEventListener(eventName, unhighlight, false)
        })

    // Handle dropped files
    dropArea.addEventListener('drop', handleDrop, false)

    function preventDefaults(e) {
        e.preventDefault()
        e.stopPropagation()
    }

    function highlight(e) {
        dropArea.classList.add('highlight')
    }

    function unhighlight(e) {
        dropArea.classList.remove('active')
    }

    function handleDrop(e) {
        var dt = e.dataTransfer
        var files = dt.files

        handleFiles(files)
    }

    let uploadProgress = []
    let progressBar = document.getElementById('progress-bar')

    function initializeProgress(numFiles) {
        progressBar.value = 0
        uploadProgress = []
        for (let i = numFiles; i > 0; i--) {
            uploadProgress.push(0)
        }
    }

    function updateProgress(fileNumber, percent) {
        uploadProgress[fileNumber] = percent
        let total = uploadProgress.reduce((tot, curr) => tot + curr, 0) / uploadProgress.length
        //console.log('update', fileNumber, percent, total)
        progressBar.value = total
        return total === 100;
    }

    function handleFiles(files) {
        files = [...files]
        initializeProgress(files.length)
        //files.forEach(uploadFile)
        files.forEach(previewFile)
    }

    function previewFile(file) {
        //console.error('file.name: ' + file.name);
        let reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onloadend = function () {
            let img = document.createElement('img')
            img.id = file.name;//.toString().replaceAll('"', '').replaceAll('.', '').replaceAll(' ', '_');
            img.src = reader.result
            document.getElementById('gallery').appendChild(img)
        }
    }

    function uploadFile(file, i) {
        var url = '/api2/uploadfile/135/3435' // TODO: change end point
        var xhr = new XMLHttpRequest()
        var formData = new FormData()
        xhr.open('POST', url, true)
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')

        // Update progress (can be used to show progress indicator)
        xhr.upload.addEventListener("progress", function (e) {
            updateProgress(i, (e.loaded * 100.0 / e.total) || 100)
        })

        xhr.addEventListener('readystatechange', function (e) {
            if (xhr.readyState == 4 && xhr.status == 200) {
                if (updateProgress(i, 100)) {
                    //$("'" + "#gallery #" + xhr.responseText.replaceAll('"', '').replaceAll('.', '').replaceAll(' ', '_') + "'").remove();//how do we handle spaces in filenames?
                    //console.error(i);
                    $('#gallery img:nth-child(' + (i + 1) + ')').hide();
                    
                    //alert('Complete') // TODO
                    return true;
                }
            }
            else if (xhr.readyState == 4 && xhr.status != 200) {
                $('#status').html(GetMessageStatus('Error: ' + xhr.responseText, 1));
                return false;
            }
        })

        formData.append('file', file)
        xhr.send(formData)
    }
        </script>

UPDATE 1

I added my code here: https://plnkr.co/edit/HHPDL6Ndc6nxPMGn?open=lib%2Fscript.js

I debugged everything and the same path is executed. However, when I select 1 image via the button and hit upload button, in function uploadFiles, on this line files = [...fileElem.files] the variable files has length 1, but when I drag and drop the same image, and hit upload button the variable files has length 0.

2 Answers

I think you need to managed the dropped images separately maybe in a array of dropped files because the files dropped in drop-area will not be considered in the File Upload html tag.

So you need to add a global variable to store dropped files array.

let droppedFiles = [];

Then in the handleDrop(e) method you need to add files in the droppedFiles array.

for (let i = 0; i < files.length; i++) {
    droppedFiles.push(files[i]);
}

Now, at the submit/upload button you need to add this also, to make sure all files should get attached. (Files from file upload tag & dropped files).

for (let i = 0; i < droppedFiles.length; i++) {
    files.push(droppedFiles[i]);
}

let droppedFiles = [];

        let btnUpload = document.getElementById("btnUpload")
        btnUpload.addEventListener('click', uploadFiles, false)

        function uploadFiles(event) {
            event.preventDefault();
            // TODO - validate file size, extension & amount
            files = [...fileElem.files];


            for (let i = 0; i < droppedFiles.length; i++) {
                files.push(droppedFiles[i]);
            }

            console.log(files.length);
            // Submit each file separately.
            //files.forEach(uploadFile)
            //check if success and if so, remove from gallery 
        }

        // This all copy & paste
        // ************************ Drag and drop ***************** //
        let dropArea = document.getElementById("drop-area")

            // Prevent default drag behaviors
            ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
                dropArea.addEventListener(eventName, preventDefaults, false)
                document.body.addEventListener(eventName, preventDefaults, false)
            })

            // Highlight drop area when item is dragged over it
            ;['dragenter', 'dragover'].forEach(eventName => {
                dropArea.addEventListener(eventName, highlight, false)
            })

            ;['dragleave', 'drop'].forEach(eventName => {
                dropArea.addEventListener(eventName, unhighlight, false)
            })

        // Handle dropped files
        dropArea.addEventListener('drop', handleDrop, false)

        function preventDefaults(e) {
            e.preventDefault()
            e.stopPropagation()
        }

        function highlight(e) {
            dropArea.classList.add('highlight')
        }

        function unhighlight(e) {
            dropArea.classList.remove('active')
        }

        function handleDrop(e) {
            var dt = e.dataTransfer
            var files = dt.files

            for (let i = 0; i < files.length; i++) {
                droppedFiles.push(files[i]);
            }

            handleFiles(files)
        }

        let uploadProgress = []
        let progressBar = document.getElementById('progress-bar')

        function initializeProgress(numFiles) {
            progressBar.value = 0
            uploadProgress = []
            for (let i = numFiles; i > 0; i--) {
                uploadProgress.push(0)
            }
        }

        function updateProgress(fileNumber, percent) {
            uploadProgress[fileNumber] = percent
            let total = uploadProgress.reduce((tot, curr) => tot + curr, 0) / uploadProgress.length
            //console.log('update', fileNumber, percent, total)
            progressBar.value = total
            return total === 100;
        }

        function handleFiles(files) {
            files = [...files];
            // fileElem= [...files];
            initializeProgress(files.length)
            //files.forEach(uploadFile)
            files.forEach(previewFile)
        }

        function previewFile(file) {
            //console.error('file.name: ' + file.name);
            let reader = new FileReader()
            reader.readAsDataURL(file)
            reader.onloadend = function () {
                let img = document.createElement('img')
                img.id = file.name;//.toString().replaceAll('"', '').replaceAll('.', '').replaceAll(' ', '_');
                img.src = reader.result
                document.getElementById('gallery').appendChild(img)
            }
        }

        function uploadFile(file, i) {
            var url = '/api2/uploadfile/135/3435' // TODO: change end point
            var xhr = new XMLHttpRequest()
            var formData = new FormData()
            xhr.open('POST', url, true)
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')

            // Update progress (can be used to show progress indicator)
            xhr.upload.addEventListener("progress", function (e) {
                updateProgress(i, (e.loaded * 100.0 / e.total) || 100)
            })

            xhr.addEventListener('readystatechange', function (e) {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    if (updateProgress(i, 100)) {
                        //$("'" + "#gallery #" + xhr.responseText.replaceAll('"', '').replaceAll('.', '').replaceAll(' ', '_') + "'").remove();//how do we handle spaces in filenames?
                        //console.error(i);
                        $('#gallery img:nth-child(' + (i + 1) + ')').hide();

                        //alert('Complete') // TODO
                        return true;
                    }
                }
                else if (xhr.readyState == 4 && xhr.status != 200) {
                    $('#status').html(GetMessageStatus('Error: ' + xhr.responseText, 1));
                    return false;
                }
            })

            formData.append('file', file)
            xhr.send(formData)
        }
  <div id="drop-area" style="border: 1px dashed">

        <span id="status"></span>
        <p>Drop files here</p>

        <input type="file" id="fileElem" multiple accept="image/*" onchange="handleFiles(this.files)">
        <label class="button" for="fileElem">Select files</label>
        <progress id="progress-bar" max=100 value=0></progress>
        <br />
        <br />
    </div>
    <div id="gallery"></div>
    <br />
    <input id="btnUpload" type="submit" class="button green small" value="Upload" />
    
    

Answered by Mohan Rajput on December 30, 2021

Add fileElem.files = files to the top of your handleFiles() method, or modify your uploadFiles() method. Currently, uploadFiles() only pulls files from fileElem. As a fix, you can set the fileElem's file list to the dropped file in handleFiles(). Thus, your new handleFiles() method would look as follows:

function handleFiles(files) {
    fileElem.files = files
    files = [...files]
    initializeProgress(files.length)
    files.forEach(previewFile)
}

Answered by citysurrounded on December 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP