6

I'm using html fileinput to upload a file with reactjs, but once I uploaded a file, I cannot call the function to upload another file, unless I refresh the page of course.

A simplified version of my code would be:

class Matrice extends React.Component {
  constructor(props) {
    super(props);
    this.fileInput = null;
  }

  uploadQuestion = async e => {
    console.log("uploading question");
    if (e.target.files[0]) {
      const form = new FormData();
      let type;
      if (e.target.files[0].type == "image/jpeg") type = ".jpg";
      if (e.target.files[0].type == "image/png") type = ".png";
      if (e.target.files[0].type == "image/gif") type = ".gif";
      // const fileName = this.props.current + type;
      form.append("files", e.target.files[0]); //filename
      form.append("ref", "exam"); // model
      form.append("refId", this.props.match.params.id); // id
      form.append("field", "media"); // name of field (image field)
      this.setState({ questionUploadLoading: true });
      const files = await strapi.upload(form);
      this.saveMontage(files, undefined, "question");
    }
  };

  render() {
    return (
      <>
        <input
          style={{ display: "none" }}
          ref={fileInput => (this.fileInput = fileInput)}
          onChange={this.uploadQuestion}
          className="file"
          type="file"
          id="imgAdd"
        />
        <button
          onClick={() => this.fileInput.click()}
          type="button"
          className="btn btn-secondary"
        >
          <i className="fas fa-image" />
        </button>
      </>
    );
  }
}

But my function uploadQuestion cannot be called again once I finished uploading a file. Namely, the console.log('uploading question') doesn't show up (the second time).

I don't know what could be the reason, but I guess that something is preventing the onChange handler as if, uploading a file the second time doesn't "changes" the trigger.

Does anybody have an idea what could cause this?

Thanks

1

4 Answers 4

9

You can reset the file input by setting its value to the empty string, and you will be able to use it again.

uploadQuestion = async (e) => {
    console.log('uploading question')
    if (e.target.files[0]) {
        // ...
        this.fileInput.value = "";
    }
}
Sign up to request clarification or add additional context in comments.

Comments

5

I had a heck of a time with this and no matter what I did from above nothing worked. Now, I've simply hardcoded the value to an empty string and I can upload over and over. I'm not even sure why this works, but I don't ever need the text value. The server cares about that. Here's a styled button using Material-UI where you never see the input, but you can upload over and over (in my case the server sends back some error and please fix your xlsx file message and I needed the user to be able to fix and try again):

import React from 'react';
import { Button } from '@material-ui/core';
import BackupIcon from '@material-ui/icons/Backup';

const UploadButton = ({ onChange, name, label, disabled }) => {
    return (
        <div className={'MuiFormControl-root MuiTextField-root'}>
            <input
                name={name}
                id='contained-button-file'
                type='file'
                accept='.csv, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
                style={{ display: 'none' }}
                onChange={onChange}
                disabled={disabled}
                value=''
            />
            <label htmlFor='contained-button-file'>
                <Button
                    color='primary'
                    aria-label='Upload scan file.'
                    variant='contained'
                    component='span'
                    startIcon={<BackupIcon />}
                    disabled={disabled}
                >
                    {label}
                    </Button>
            </label>
        </div>
    );
};

export default UploadButton;

Comments

2

You need to set the state for image that to be upload there is flow the step

  1. Set a state for upload file in your Constructor (uploadFile:null)

  2. Add a function for handle file Change

  3. Use state upload(uploadFile) into uploadQuestion() instead of e.target.value[0]

  4. After Upload setState back to uploadFile:null

  5. set the file input onChange={this.fileHandle}

class Matrice extends React.Component {
    constructor(props) {
        super(props);
        this.state:{
            uploadFile:null
        }
        this.fileInput = null;
        this.fileHandle = this.fileHandle.bind(this)
    }

fileHandle (e, a) {
    e.preventDefault()
    this.setState({ upload: e.target.files[0] })
  };

uploadQuestion = async (e) => {
    console.log('uploading question')
    if (e.target.files[0]) {
        const form = new FormData();
        let type;
        if (e.target.files[0].type == 'image/jpeg') type = '.jpg'
        if (e.target.files[0].type == 'image/png') type = '.png';
        if (e.target.files[0].type == 'image/gif') type = '.gif';
        // const fileName = this.props.current + type;
        //Use state upload(uploadFile) into uploadQuestion() instead of e.target.value[0]
        file.append('images', this.state.uploadFile, this.state.uploadFile.name) //filename
        form.append('ref', 'exam'); // model
        form.append('refId', this.props.match.params.id) // id
        form.append('field', 'media') // name of field (image field)
        this.setState({questionUploadLoading: true})
        const files = await strapi.upload(form);
        this.saveMontage(files, undefined, 'question')
        //After Upload setState back to uploadFile:null
        this.setState({uploadFile:null})
    }

}

if you like to valid in onChange you can modify function as Below


fileHandle (e) {
    e.preventDefault()
    if (!e.target.files[0].name.match(/.(jpg|jpeg|png|gif)$/i)) {
      this.setState({ errorMsg: 'Please upload valid file. Allowed format jpg, jpeg, png, gif' })
      return false
    } else {
      this.setState({ upload: e.target.files[0], errorMsg: '' })
    }
  };

Comments

1

Just handle it using click event

const handleClick = event => {
    const { target = {} } = event || {};
    target.value = "";
  };

<input type="file" onChange={handleChange} onClick={handleClick} />

Comments

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.