Josh Hunt
Josh Hunt

Reputation: 14521

How to POST a file (from File API) from drag and drop

I have a file-upload page where the file is selected via drag and drop. Because the file is dropped in (rather than using a traditional field), I have the file exposed to me through the javascript File API.

I've been reading this article from Mozilla, but I am not all that interested in asynchronously uploading it (as I have some other data that needs to be submitted with the file, but all the resources I have managed to find are doing it with XHR.

Here's what I've managed to piece together:

function handleFileSelect(evt) {
    evt.toElement.className = "";
    evt.stopPropagation();
    evt.preventDefault();

    var files = evt.dataTransfer.files; // FileList object.

    // files is a FileList of File objects. List some properties.
    var output = [];
    for (var i = 0, file; file = files[i]; i++) {
        var f = file;

        var reader = new FileReader();
        reader.onload = function(e) {
          var bin = e.target.result;
          // bin is the binaryString
        };
        reader.readAsBinaryString(file);

        var xhr = new XMLHttpRequest();
        xhr.open("POST", "{% url micro-upload %}");
        xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
        xhr.sendAsBinary(bin);

        output.push('<li><strong>Uploaded:</strong><em>', escape(f.name), '</em> (', f.type || 'n/a', ') - ',
                    f.size, ' bytes, last modified: ',
                    f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a',
                    '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
}

However server side, Django does not like this. It complains about malformed POST data.

Ideally, my solution I think would be this:

  1. User drag-and-drops file onto page
  2. File is added to a hidden file <input>
  3. File is POSTed along with the rest of the form data.

I am aware that most browsers let you drag files onto a file <input>, but I want to have a larger drop target with custom styling.

Upvotes: 1

Views: 1867

Answers (1)

ebidel
ebidel

Reputation: 24119

xhr.sendAsBinary() is not standard. Have you thought about using FormData? That would allow you to attach the file (and other properties) to a mime multipart request...essentially what a form.post() does. See my response here for code how to do that.

Upvotes: 1

Related Questions