Skip to content

Instantly share code, notes, and snippets.

@ihgrant
Created December 1, 2016 17:47
Show Gist options
  • Save ihgrant/7fe2d7868a453dd09b1a0c1eea0a2c0b to your computer and use it in GitHub Desktop.
Save ihgrant/7fe2d7868a453dd09b1a0c1eea0a2c0b to your computer and use it in GitHub Desktop.
file upload with dropzone

naïve approach

  • rely on files property being set
  • fails because while clicking on the input and selecting files will set the property correctly, dragging and dropping does not actually interact with the input and set the property. The property cannot be set manually (react-dropzone/react-dropzone#131) using javascript for security reasons.
  • thus when the form is submitted the file input has no files property and nothing is uploaded.

let's use javascript, then!

  • submit the form using fetch, create a FormData from the form and manually set the files field using state set using the onDrop callback from Dropzone
  • only set the files field if it's not set (because the user could have clicked and chosen files instead of dragging and dropping)
  • FormData has a great API for inspecting its keys and values! I'll use FormData#getAll() and see if the files are populated
  • works great in chrome and ff!

but it errors in safari (and IE)

  • they only support instantiation and FormData#append().
  • we need some other way of knowing whether to use files from state or the input
  • in onDrop, check to see if the event target is the file input and if its files property has length
  • if either condition is false, set 'filesWereDropped' state to true
  • in form submit, check this value in state to see what to do.
    onDrop(acceptedFiles, rejectedFiles, e) {
        this.setState({
            files: acceptedFiles,
            filesWereDropped: !e.target.files || e.target.files.length === 0
        });
    }
    onSubmit(e) {
        e.preventDefault();
        let formData = new FormData(this.formRef);

        if (this.state.filesWereDropped) {
            /* if the file input has no files, check state for files and add
             * those to the form data. This is necessary because dragging
             * and dropping does set the files attribute of the file input,
             * and it is not possible to set it from javascript for
             * security reasons.
             */
            this.state.files.forEach(file => {
                formData.append('myfiles', file, file.name);
            });
        }
        
        // then POST your formData!
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment