action function is required with antd upload control, but I dont need it

35,596

Solution 1

TL;DR

Override <Upload/> default upload AJAX implementation with a simulated successful upload.

Solution Demo:
Edit antd upload component as file selector

Full Answer

It seems that you are trying to use andt's <Upload/> component simply as file selector, due to the fact that you append the file to formData by yourself. The reason for never hitting the point where status === "done" is because the file is not really uploaded to anywhere.
Thus, you don't need the file to be uploaded automatically like it should OOB.
All you need is that the onChange will send you the selected file and you can save it somewhere in the state tree.
<Upload/> renders another component (rc-upload) as its child which handles the actual AJAX upload. You can override this behaviour by passing a customRequest prop to <Upload/>(which will be passed to rc-upload component).

You can see here which options are passed to the request function. Here is an implementation of a dummy request function:

const dummyRequest = ({ file, onSuccess }) => {
  setTimeout(() => {
    onSuccess("ok");
  }, 0);
};

Then you can pass it to <Upload customRequest={dummyRequest}/>
onChange will still be triggered, but this time with the "done" status, since the dummy request function simulates a flow of successful upload.

Solution 2

According to the official documentation Upload manually:

Upload files manually after beforeUpload returns false.

beforeUpload(file) {
    const isJPG = file.type === 'image/jpeg';
    if (!isJPG) {
      message.error('You can only upload JPG file!');
    }
    return false;
}

Solution 3

Extending to @Quincy's answer, you can also use shorthand on component something like this,

<Upload beforeUpload={() => false} />
Share:
35,596
Luis Valencia
Author by

Luis Valencia

Updated on January 16, 2022

Comments

  • Luis Valencia
    Luis Valencia over 2 years

    I am using ant design components and I have an upload input: https://ant.design/components/upload/

    According to the documentation, action is required on the props.

    However I dont need the file to be posted to an url when uploaded, I need the entire FORM to be submited to a rest endpoint (check handlesubmit function)

    Trying to go through the documentation, I used the handlechange event to add the file to the state, but the STATUS is never done, so that line is never hit.

    What am I missing here?

    import React, { Component } from 'react';
    import { Input, Upload , Icon, message} from 'antd';
    import Form from '../../components/uielements/form';
    import Checkbox from '../../components/uielements/checkbox';
    import Button from '../../components/uielements/button';
    import Notification from '../../components/notification';
    import { adalApiFetch } from '../../adalConfig';
    
    const FormItem = Form.Item;
    
    class RegisterTenantForm extends Component {
        constructor(props) {
            super(props);
            this.state = {TenantId: '', TenantUrl: '', CertificatePassword: '', confirmDirty: false, loading: false, buttondisabled: true};
            this.handleChangeTenantUrl = this.handleChangeTenantUrl.bind(this);
            this.handleChangeCertificatePassword = this.handleChangeCertificatePassword.bind(this);
            this.handleChangeTenantId= this.handleChangeTenantId.bind(this);
            this.handleSubmit = this.handleSubmit.bind(this);
            this.handleupload = this.handleupload.bind(this);
            this.handleTenantIdValidation = this.handleTenantIdValidation.bind(this);
            this.handleTenantAdminUrl = this.handleTenantAdminUrl.bind(this);
    
        };
    
        handleChangeTenantUrl(event){
            this.setState({TenantUrl: event.target.value});
        }
    
        handleChangeCertificatePassword(event){
            this.setState({CertificatePassword: event.target.value});
        }
    
        handleChangeTenantId(event){
            this.setState({TenantId: event.target.value});
        }
    
        beforeUpload(file) {
            const isJPG = file.type === 'image/jpeg';
            if (!isJPG) {
              message.error('You can only upload JPG file!');
            }
        }
    
        handleupload(info){
            //let files = e.target.files;
            if (info.file.status === 'uploading') {
                this.setState({ loading: true });
                return;
            }
    
            if (info.file.status === 'done') {
                this.setState({ loading: false });
                this.setState({ 'selectedFile': info.file });
            }
    
        }
    
        handleTenantIdValidation(rule, value, callback){
            const form = this.props.form;
            const str = form.getFieldValue('tenantid');
    
            var re = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
            if (str && !str.match(re)) {
                this.setState({buttondisabled: true});
                callback('Tenant id is not correctly formated id');            
            } 
            else {
                this.setState({buttondisabled: false});
                callback();
            }
        }
    
        handleTenantAdminUrl(rule, value, callback){
            const form = this.props.form;
            const str = form.getFieldValue('tenantadminurl');
    
            var re = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/i;
            if (str && !str.match(re)) {
                this.setState({buttondisabled: true});
                callback('Tenant Url is not correctly formated id');
            } 
            else {
                this.setState({buttondisabled: false});
                callback();
            }
        }
    
    
        handleSubmit(e){
            e.preventDefault();
            this.props.form.validateFieldsAndScroll((err, values) => {
                if (!err) {
                    /*Notification(
                    'success',
                    'Received values of form',
                    JSON.stringify(values)
                    );*/
    
                    let data = new FormData();
                    //Append files to form data
                    data.append("model", JSON.stringify({ "TenantId": this.state.TenantId, "TenantUrl": this.state.TenantUrl, "CertificatePassword": this.state.CertificatePassword }));
                    //data.append("model", {"TenantId": this.state.TenantId, "TenantUrl": this.state.TenantUrl, "TenantPassword": this.state.TenantPassword });
    
                    let files = this.state.selectedFile;
                    for (let i = 0; i < files.length; i++) {
                      data.append("file", files[i], files[i].name);
                    }
    
                    const options = {
                      method: 'put',
                      body: data,
                      config: {
                        headers: {
                          'Content-Type': 'multipart/form-data'
                        }
                      }
                    };
    
                    adalApiFetch(fetch, "/Tenant", options)
                      .then(response => response.json())
                      .then(responseJson => {
                        if (!this.isCancelled) {
                          this.setState({ data: responseJson });
                        }
                      })
                      .catch(error => {
                        console.error(error);
                    });
                }
            });      
        }
    
    
    
        render() {
            const { getFieldDecorator } = this.props.form;
    
            const formItemLayout = {
            labelCol: {
                xs: { span: 24 },
                sm: { span: 6 },
            },
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 14 },
            },
            };
            const tailFormItemLayout = {
            wrapperCol: {
                xs: {
                span: 24,
                offset: 0,
                },
                sm: {
                span: 14,
                offset: 6,
                },
            },
            };
            return (
                <Form onSubmit={this.handleSubmit}>
                    <FormItem {...formItemLayout} label="Tenant Id" hasFeedback>
                    {getFieldDecorator('tenantid', {
                        rules: [
                        {
                            required: true,
                            message: 'Please input your tenant id',
                        },
                        {
                            validator: this.handleTenantIdValidation
                        }],
                    })(<Input name="tenantid" id="tenantid" onChange={this.handleChangeTenantId}/>)}
                    </FormItem>
                    <FormItem {...formItemLayout} label="Certificate Password" hasFeedback>
                    {getFieldDecorator('certificatepassword', {
                        rules: [
                        {
                            required: true,
                            message: 'Please input your password!',
                        }
                        ],
                    })(<Input type="password" name="certificatepassword" id="certificatepassword" onChange={this.handleChangeCertificatePassword}/>)}
                    </FormItem>
                    <FormItem {...formItemLayout} label="Tenant admin url" hasFeedback>
                    {getFieldDecorator('tenantadminurl', {
                        rules: [
                        {
                            required: true,
                            message: 'Please input your tenant admin url!',
                        },
                        {
                            validator: this.handleTenantAdminUrl
                        }],
                    })(<Input name="tenantadminurl" id="tenantadminurl"  onChange={this.handleChangeTenantUrl} />)}
                    </FormItem>
                    <FormItem {...formItemLayout} label="Certificate File">
                        <Upload  onChange={this.handleupload} beforeUpload={this.beforeUpload}>
    
                            <Button >
                                <Icon type="upload" /> Click to Upload
                            </Button>
                        </Upload>
    
                    </FormItem>
                    <FormItem {...tailFormItemLayout}>
                        <Button type="primary" htmlType="submit" disabled={this.state.buttondisabled}>
                            Register tenant
                        </Button>
                    </FormItem>
                </Form>
            );
        }
    }
    
    const WrappedRegisterTenantForm = Form.create()(RegisterTenantForm);
    export default WrappedRegisterTenantForm;