Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No files in input after drag&drop files when submitting form #880

Closed
FredoVelcro-zz opened this issue Sep 20, 2019 · 4 comments
Closed

No files in input after drag&drop files when submitting form #880

FredoVelcro-zz opened this issue Sep 20, 2019 · 4 comments

Comments

@FredoVelcro-zz
Copy link

FredoVelcro-zz commented Sep 20, 2019

I use a react drop zone for multiple files upload.
When i add file with the "add" button or "click", submit data are ok.
But, when i add files using drag'n drop, if i submit, i have no files in the request...

import React, {useMemo} from "react"
import ReactDOM from "react-dom"
import {useDropzone} from 'react-dropzone';

const baseStyle = {
    padding: '20px',
    borderWidth: 2,
    borderRadius: 2,
    borderColor: '#eeeeee',
    borderStyle: 'dashed',
    backgroundColor: '#fafafa',
    color: '#666',
    outline: 'none',
    transition: 'border .24s ease-in-out',
    minHeight: '350px',
    height: '350px',
    overflowX: "auto",
    overflowY: "auto"
};

const activeStyle = {
    borderColor: '#2196f3'
};

const acceptStyle = {
    borderColor: '#00e676'
};

const rejectStyle = {
    borderColor: '#ff1744'
};

/**
 * @param size
 * @returns {string}
 */
function fileSizeFormat(size) {
    if ((size / 1024) > 1024) {
        return Math.ceil(size / 1024 / 1024).toFixed(1) + ' Mo';
    }

    if (size < 1024) {
        return size + ' Octets';
    }

    return Math.ceil(size / 1024) + ' Ko';
}

function DropzoneWithoutClick(props) {

    const {
        getRootProps,
        getInputProps,
        open,
        isDragActive,
        isDragAccept,
        isDragReject,
        acceptedFiles
    } = useDropzone({
        accept: props.accept,
        onDrop: files => {
            files.map(function (file, index) {
                console.log(getInputProps)
                console.log("file ", index, ": ", file);
            });
        },
        multiple: props.multiple,
        minSize: 1,
        maxSize: props.maxSize
    });

    //console.log(acceptedFiles);

    const files = acceptedFiles.map((file, index) =>
        <div className="row mb-2" key={file.path} onClick={event => event.stopPropagation()}>
            <div className="col-6">
                {file.path} - {fileSizeFormat(file.size)}
            </div>
            <div className="col-6">
                <textarea name={props.commentName + "[" + index + "]"} data-file-id={file.path}
                          placeholder="Commentaire..."
                          cols={40} rows={3}
                          onClick={event => event.stopPropagation()}></textarea>
            </div>
        </div>
    );

    const style = useMemo(() => ({
        ...baseStyle,
        ...(isDragActive ? activeStyle : {}),
        ...(isDragAccept ? acceptStyle : {}),
        ...(isDragReject ? rejectStyle : {})
    }), [
        isDragActive,
        isDragReject
    ]);

    let inputName = props.inputName + (props.multiple ? "[]" : "");

    return (
        <div>
            <button type="button" onClick={open}>
                {props.textButtonAdd}
            </button>
            <div>
                <div {...getRootProps({style})}>
                    <input name={inputName} {...getInputProps()} />
                    <h3>{props.textDragDrop}</h3>
                    <aside>
                        {files.length > 0 && <h4>Files to upload</h4>}
                        {files}
                    </aside>
                </div>
            </div>
        </div>
    );
}

let dropZone = document.querySelector("#dropzone");
ReactDOM.render(
    <DropzoneWithoutClick textDragDrop={dropZone.dataset.textDragDrop}
                          textButtonAdd={dropZone.dataset.textButtonAdd}
                          multiple={dropZone.dataset.multiple === "1"}
                          accept={dropZone.dataset.acceptMime}
                          inputName={dropZone.dataset.inputFieldName}
                          commentName={dropZone.dataset.commentFieldName}
                          maxSize={dropZone.dataset.maxFileSize}
    />,
    dropZone
)

The html markup :

<form name="file_deposit" method="post" enctype="multipart/form-data">

    <div id="dropzone"
        data-text-drag-drop="Drag files here"
        data-text-button-add="Add files"
        data-multiple="1"
        data-accept-mime="image/*"
        data-input-field-name="file_deposit[files]"
        data-comment-field-name="file_deposit[comments]"
        data-max-file-size="2147483648"></div>

        <button type="submit">Send</button>
</form>

Any help welcome ! thanks a lot

@FredoVelcro-zz
Copy link
Author

It seems that the drag'n drop doesn't set the new files to the input.
If you add a file A with the "add" button (or click on dropzone), and then add a file B with drag'n drop, when you submit the form you will have File A... (but file B is shown on dropzone)

@rolandjitsu
Copy link
Collaborator

@FredoVelcro next time you open an issue, please take the time to create a small codepen/codesandbox to illustrate your issue.

And yes, we do not update the input when you drag 'n' drop a file. You have the onDrop cb which gives you the files or the acceptedFiles property returned by the useDropzone hook, so use that.

Otherwise you're welcome to make a proposal for a different behavior and implement in a PR.

@FredoVelcro-zz
Copy link
Author

thank you for your help

@dwjohnston
Copy link

If anyone needs it, you can send the files along with form submissions, by munging the files into a hidden file input.

import React, {useRef} from 'react';
import {useDropzone} from 'react-dropzone';

function Dropzone(props) {
  const {required, name} = props; 

  const hiddenInputRef = useRef(null);

  const {getRootProps, getInputProps, open, acceptedFiles} = useDropzone({
    // Disable click and keydown behavior
    noClick: true,
    noKeyboard: true, 
    onDrop: (incomingFiles) => {

      console.log(hiddenInputRef);
      if (hiddenInputRef.current) {


        // Note the specific way we need to munge the file into the hidden input
        // https://stackoverflow.com/a/68182158/1068446
        const dataTransfer = new DataTransfer();
        incomingFiles.forEach((v) => {
          dataTransfer.items.add(v);
        });
        hiddenInputRef.current.files = dataTransfer.files;
      }
    }
  });

  const files = acceptedFiles.map(file => (
    <li key={file.path}>
      {file.path} - {file.size} bytes
    </li>
  ));

  return (
    <div className="container">
      <div {...getRootProps({className: 'dropzone'})}>
        {/*
          Add a hidden file input 
          Best to use opacity 0, so that the required validation message will appear on form submission
        */}
        <input type ="file" name={name} required={required} style ={{opacity: 0}} ref={hiddenInputRef}/>
        <input {...getInputProps()} />
        <p>Drag 'n' drop some files here</p>
        <button type="button" onClick={open}>
          Open File Dialog
        </button>
      </div>
      <aside>
        <h4>Files</h4>
        <ul>{files}</ul>
      </aside>
    </div>
  );
}


<form onSubmit={(e) => {
  e.preventDefault(); 

  // Now get the form data as you regularly would
  const formData = new FormData(e.currentTarget);
  const file =  formData.get("my-file");
  alert(file.name); 
}}>
  <Dropzone name ="my-file" required/>
  <button type="submit">Submit</button>
</form>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants