web-dev-qa-db-ja.com

antdアップロードコントロールにはアクション関数が必要ですが、必要ありません

私はant設計コンポーネントを使用しており、アップロード入力があります: https://ant.design/components/upload/

ドキュメントによると、アクションは小道具に必要です。

しかし、アップロード時にファイルをURLに投稿する必要はありません、フォーム全体を残りのエンドポイントに送信する必要があります(handlesubmit機能を確認してください)

ドキュメントを調べてみると、handlechangeイベントを使用してファイルを状態に追加しましたが、STATUSは実行されないため、その行はヒットしません。

ここで何が欠けていますか?

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;
7
Luis Valencia

TL; DR

_<Upload/>_ default upload AJAX実装をシミュレートし、アップロードを成功させてオーバーライドします。

ソリューションデモ:
Edit antd upload component as file selector

完全な回答

andtの_<Upload/>_コンポーネントを単にファイルセレクターとして使用しようとしているようです。これは、自分でファイルをformDataに追加するためです。 _status === "done"_に到達しない理由は、ファイルが実際にどこにもアップロードされていないためです。
したがって、OOBのようにファイルを自動的にアップロードする必要はありません。
必要なのは、onChangeが選択したファイルを送信し、状態ツリーのどこかに保存できることだけです。
_<Upload/>_は、実際のAJAXアップロードを処理する子として別のコンポーネント( rc-upload )をレンダリングします。この動作は、 customRequest propを_<Upload/>_(_rc-upload_コンポーネントに渡す)に渡す。

here どのオプションがリクエスト関数に渡されるかを見ることができます。ダミーのリクエスト関数の実装は次のとおりです。

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

次に、それを_<Upload customRequest={dummyRequest}/>_に渡すことができます
onChangeは引き続きトリガーされますが、今回は_"done"_ステータスを使用します。これは、ダミーの要求関数が正常なアップロードのフローをシミュレートするためです。

17
Ramy Ben Aroya

公式ドキュメントによると 手動でアップロード

beforeUploadfalseを返した後にファイルを手動でアップロードします。

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