0

Please apologize me for posting the image, but unfortunately my issue can be represented better through image only.

I am making a file upload using antd upload component.

Once I finished uploading files one by one using multiple upload mode, I get the result as following image.

enter image description here

Here the first two objects are ignored when submitting the form after file upload.

The form data for api call has been sent like this, (Content as undefined for first two objects but works for the last where content value was provided as binary)

enter image description here

Simple working example:

Edit antd-file-upload-validation-in-reactjs (forked)

After uploading 2 and more files, please note the console.log(e.fileList); in line no.28 of demo.tsx. The result will be like, (First object with name as File but second one as normal object)

enter image description here

I would like to have both object values in the same format as object. Could you please guide me why after file upload, the last one have normal object and other previous uploaded have File object?

If I upload three files then I have to call three api's in which the payloads are as follows,

Payload of first file api call https://i.sstatic.net/s23in.png

Payload of second api call https://i.sstatic.net/ZHnKT.png

Payload of third api call https://i.sstatic.net/eqYSd.png

So only the last payload has the content as binary whereas other two are undefined which prevents the image from uploading.

14
  • Seems whatever the last item uploaded is still an Object instead of a File in whatever that normFile callback is receiving. If you log the updated fileList in an useEffect hook you'll see they are all File types. What are you trying to do? Commented Apr 20, 2022 at 23:59
  • Is all you want to convert the File to a normal object? if so you can connot convert it directly but you can create a new object and set the values your self from the original file obj. e.g. """ const fileObj = { uid:file.uid, lastModified: file.lastModified, lastModifiedDate: file.lastModifiedDate, name: file.name, size: file.size, type: file.type }; setFileList((state) => [...state, fileObj]); """ something like that. Commented Apr 21, 2022 at 0:28
  • @DrewReese, Once files are uploaded I will call api for each uploaded one in which the content is passed as undefined for first n files and only for last file the content is binary. Please take a look at the comments under the answer given for the question. I have attached step by step screenshots. If I upload 3 files then for first 2, the content is not passed(undefined) down to the payload. So only last file is getting saved into DB as it is the only one have content in payload. Commented Apr 21, 2022 at 2:09
  • I'm not sure what you are trying to do in the sandbox, but if you need the Object object you could grab that and cache in state where you are logging it. Otherwise, adabuyaman's suggestion seems valid. Commented Apr 21, 2022 at 2:26
  • @DrewReese, In sandbox if we upload three files then we see the first two object as with key as File whereas for the last one we have as normal object and I feel this cause issue while uploading to the api which gives content as undefined for first two and works for the last one. So seeking help how to solve this issue as I am also not sure why it happens bro. Commented Apr 21, 2022 at 2:37

1 Answer 1

2

You are sending a file object. You need to use FormData to send files. It allows you to set key/value pairs. I have created a small example with complete form submission. Also attach some screenshot.

import { useState, useMemo } from 'react';
import { Upload, Button, message, Form, Input } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { UploadFile } from 'antd/lib/upload/interface';
import { RcFile } from 'rc-upload/lib/interface';
import { POST } from '../../../utils/https';
import axios from 'axios';

interface FormRule {
    title: string;
    attachment?: { file: RcFile; fileList: RcFile[] };
}

const Uploader = () => {
    const [fileList, setFileList] = useState<UploadFile<any>[]>([]);
    const [form] = Form.useForm<FormRule>();

    const validateFileType = ({ type, name }: UploadFile, allowedTypes: string[] = ['image/png', 'image/jpeg']) => {
        return allowedTypes.includes(type!);
    };

    const uploadProps = useMemo(
        () => ({
            multiple: true,
            beforeUpload: (file: UploadFile) => {
                const isAllowedType = validateFileType(file);
                if (!isAllowedType) {
                    message.error(`${file.name} is not PNG file`);
                    return false;
                }
                setFileList((prev) => [...prev, file]);
                return false;
            },
            onRemove: (file: UploadFile) => {
                setFileList((prev) => prev.filter((item) => item.uid !== file.uid));
            }
        }),
        []
    );

    const onSubmit = async (data: FormRule) => {
        // You cannot send files like normal data. You need to convert it into buffer...
        // Use FormData and attach everything you want to send to send to backend
        // If you are using node.js, use multer or any other package of your choice to get all files
        // and get Files from req.files and data from req.body
        let formData = new FormData();
        formData.append('title', data.title);

        // Don't get attachment files from data, use fileList State because
        // it you use attachment from data, it will have all the files that
        // should be not accepted. For example, upload one png file and 1 file other than png or jpeg i.e. txt,
        // it will have txt file + png file.
        if (!!fileList.length) {
            for (const item of fileList) {
                formData.append('attachment', new Blob([item as any]));
            }
        }

        // await axios('..', { data: formData, method: 'POST' });
    };

    return (
        <Form form={form} onFinish={onSubmit} layout='vertical'>
            <Form.Item label='Title' name='title' rules={[{ required: true }]}>
                <Input />
            </Form.Item>
            <Form.Item name='attachment' rules={[{ required: true }]}>
                <Upload {...uploadProps} fileList={fileList}>
                    <Button icon={<UploadOutlined />}>Upload png only</Button>
                </Upload>
            </Form.Item>

            <Button type='primary' htmlType='submit'>
                Submit
            </Button>
        </Form>
    );
};

export default Uploader;

enter image description here

Sign up to request clarification or add additional context in comments.

6 Comments

Also here I will call api for each uploaded one separately not all at once. After uploading all files, click on submit will call three attachment api calls if I uploaded three files and pass down separate payload for each from the list. Here the attachmentName and other properties are included for all the uploaded one but only content is not getting assigned except the last one.
Any reason for sending separate api calls for each file? You can achieve the same with a single api call. Second it should be fine if you don't get originFileObj. We just need the file and the file already have all the attributes that you want to attach. Just make a blob of each file just like i created a blob in content. Don't use originFileObj just use the same object and convert in into blob.
My only question is why are you attaching type, name & other attributes for a single file explicitly?
I have fixed the issue with creating a new object that has originFileObj . The reason I need to have type, name and other attributes is that that is how the BE api call was made and it helps in storing the information in DB.
You can get the attributes of a file on the backend side. It doesn't seem ideal to explicitly add attributes with each file. Every time when upload a file you have to attach required attributes. Best of luck
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.