2

I tried for getting the image path with Dropzone in this way {...form.getInputProps("tourImages")} but it gives undefined . Also, I tried getting an image input with useState hooks, image path is displaying but, it is not displaying inside of form. Please, see the below :

      const getImage = (imageFile: any) => {
           setImageUpload(imageFile[0].path);
      };
      const [imageUpload, setImageUpload] = useState( );
    
      const form = useForm({
        schema: joiResolver(schema),
        initialValues: {
          name: "",
          sername: "",
          email: "",
          tourImages : "" ,
          imageUpload,
         
        },
      });

 <Dropzone
                    onDrop={(files) => {
                      getImage(files);
                    
                    }}
                    onReject={(files) => console.log("rejected files", files)}
                    maxSize={3 * 1024 ** 2}
                    accept={IMAGE_MIME_TYPE}
                    {...form.getInputProps("tourImages")}
                  >
                    {(status) => dropzoneChildren(status, theme)}
                  </Dropzone>
    
Farhad
  • 31
  • 1
  • 3

2 Answers2

3

With Mantine dropzone provider you could upload your files with files parameter in onDrop={} method. This onDrop function calls after file selected from user successfully. So after file selection you will able to upload your files to upload server with multipart/form-data request using Fetch Api like shown below. If you want to validate upload url. You should pass api returned url string to react state in the end of the onDrop() method.
Example usage of Dropzone:

export default function DropzoneExample() {
    return (
        <Dropzone
            multiple={false}
            onDrop={(files) => {
                console.log(files);
                const formData = new FormData();
                formData.append('file', files[0]);
                fetch('http://MY_UPLOAD_SERVER.COM/api/upload', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'multipart/form-data'
                    },
                    body: formData
                }).then(res => {
                    const respJson = res.json();
                    // console.log("File uploaded", respJson);
                    // TODO: Update ui and states....
                    // setUploads(respJson.url);
                    return respJson;
                }).catch(err => {
                    console.log("File upload error", err);
                    // TODO: Update ui and states with error....
                });

            }}
            onReject={(files) => console.log('rejected files', files)}
            accept={IMAGE_MIME_TYPE}
        >
            {(status) => dropzoneChildren(status, theme)}
        </Dropzone>
    );
}

const dropzoneChildren = (status: DropzoneStatus, theme: MantineTheme) => (
    <Group position="center" spacing="xl" style={{ minHeight: 220, pointerEvents: 'none' }}>
        <ImageUploadIcon status={status} style={{ color: getIconColor(status, theme) }} size={80} />

        <div>
            <Text size="xl" inline>
                Drag images here or click to select files
            </Text>
            <Text size="sm" color="dimmed" inline mt={7}>
                Attach as many files as you like, each file should not exceed 5mb
            </Text>
        </div>
    </Group>
);
  • 1
    What if I don't want to upload the file right after the onDrop event but after pressing the submit button? – Patrik Krehák Oct 13 '22 at 13:17
  • Super helpful, thank you! As noted in https://stackoverflow.com/questions/36067767/how-do-i-upload-a-file-with-the-js-fetch-api#comment98412965_36082038, however, the POST request only works for me if I leave the `Content-Type` header implicit (i.e. unset). – digitalifeforms Jul 31 '23 at 20:10
0

Just spent hours banging my head on this one. There's actually an issue with the underlying react dropzone implementation, it doesn't allow for normal use of the underlying <input type="file">.

The onDrop prevents the normal updating of the input's value. This results in a 0 byte file being sent in the request. You can also tell because the name will be ''.

The solution I came up with to allow for normal form usage (I'm using Remix):

const fileInput = useRef<HTMLInputElement>(null);
const _onDrop = (files: FileWithPath[]) => {
  if (!fileInput.current) {
    throw new Error("Dropzone input ref is not set yet")
  }
  const dataTransfer = new DataTransfer();
  files.forEach(f => dataTransfer.items.add(f));
  fileInput.current.files = dataTransfer.files;
  // Call an *additional* onDrop if you want
  if (onDrop) {
    onDrop(files);
  }
}
...
return (
  ...
  <input type="file" hidden ref={fileInput} name={name}/>
  <Dropzone onDrop={_onDrop} ... other props ...>
...

I'll try and get to a PR but hopefully this helps anyone else who's struggling.

Cheruvian
  • 5,628
  • 1
  • 24
  • 34