21

Using React v16.1, on a local development server. I have a simple component to upload a file here:

class FileImporter extends React.Component {
    constructor(props) {...}
    importFile(e) {
      // import the file here, not firing
    }
    render() {
      return (<input type="file" onChange={this.importFile.bind(this)} />);
    }
}    

The function importFile never fires. I've tried binding onChange in the following ways:

onChange={e => this.importFile(e)}
onChange={this.importFile.bind(this)}
onChange={this.importFile}

I've tried using react-file-reader-input and react-file-reader, and just a raw input tag like in the snippet. None of them fire the onChange handler. The system file upload dialog shows up, but on selecting a file nothing happens. How can I get the onChange event to fire?

13 Answers 13

40

For others who google here: I had a similar issue and the solution I found was that my <input> was being removed from the DOM after clicking the button to open the file picker. (It was inside a drop down.)

Clicking the input still showed the file picker, but that also caused the drop down to hide, thus removing the input from the DOM. After selecting a file the onChange never fired. I moved the input to a place that it wouldn't be removed from the DOM and things began to work again.

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

8 Comments

Any real solution instead of this workaround? I got this problem because my input is in a popover. Yes, I could confirm the problem went away when I moved the input outside of the popover. However, I really need to make it work when it's inside of the popover.
I don't know if I would call this a workaround. No <input/> in the DOM, browser can't do anything. To you question though: Another approach that comes to mind could be to use styles to set display:none when you want the popup to be hidden. That way the popup is still in the DOM, as is the <input/>. (* I didn't test this myself, but should work *)
after 2 hours of heavy workout, i found this answer. Certainly the element should remain in DOM
My problem was: whenever I clicked on file input, file picker would open. But file would not selected on "onchange" event and file picker would keep getting opened. My design was like, the <input type="file"> was inside the div box. Earlier I styled the input file like this css (position: absolute; z-index: 0; opacity: 0; filter: alpha(opacity=0)). The reason for this style is, I wanted to make input focusable as I was under impression that control is only focusable if it has space on the page. But after reading this comment, I kept the input as only "display:none" and it worked :)
I still don't understand though as in why file picker was keep getting reopened
|
20

I had another case where the input was hidden and I had a button which triggers the file selection dialog for the input.

The app showed validations on the file(Don't worry about this, may be just consider a case where I told user to do some changes in the file and reupload).

So when user tried to re-upload the same file again, it did not trigger on change the second time. But if user chose a different file, it worked.

This was because I did not clear the file input's value the first time after the first time user upload was incorrect. So somehow browser thought that the file is same so do not trigger onchange.

Interestingly, when I set input's value to blank string(Specifically in my react project, I had a ref to the input, so I did inputRef.current.value = '' in react) and it worked.

Comments

15

Use onInput instead of onChange

                <div className="profile-form-buttons centercontents">
                    <input className="form-compo"
                        type="file" 
                        name="file-uploader" 
                        id="file-uploader"  
                        onInput={imageUpdate}
                        style={{display:"none"}}
                        />
                </div>

Comments

10

I have experienced the same issue. The problem was that I have the same id for the multiple inputs. Once I've set a unique id for each input problem was solved. Thanks

<label htmlFor="file-input-id">Upload</label>
<input type="file" id="file-input-id" onChange={this.onSelectImage} />

Comments

4

When firing the event for the second time, with the same file selected as the first time, onInput/onChange doesn't work for me. I tried to analyze the root cause.Event type onInput/onChange doesn't matter. If the same file is selected for the second time, the input component retains the old filename in component memory, so onInput/onChange is not triggered.

Solution: Clear the input element's current value

const fileInput = useRef<HTMLInputElement>(null);
const handleChange = () => {
      // SOME LOGIC
      fileInput.current.value = '';
};

2 Comments

Could you please show how you connect your <input> to the fileInput ref?
Using Typescript, I got the error 'fileInput.current' is possibly 'null', so I had to wrap it: if (fileInput.current) {fileInput.current.value = ''}
2

For functional component, we can use onInputCapture or onChangeCapture.

We can track on this Issue - Diff b/w onChange and onInput and StackOverflow - Difference between onChange and onInput.

TS definition onInputCapture and onChangeCapture, React TS.

    onChange?: FormEventHandler<T> | undefined;
    onChangeCapture?: FormEventHandler<T> | undefined;
    onInput?: FormEventHandler<T> | undefined;
    onInputCapture?: FormEventHandler<T> | undefined;

MDN Docs - GlobalEventHandlers.oninput

const FileSelector = () => (
    <input
        type="file"
        onInputCapture={(e) => console.log(e.target)}
        accept={".xlsx"}
        multiple={false}
    />
);

1 Comment

When I used onChange I catched that the input field wasn't showing how many items I have selected which resulted in the files property being empty whenever I tried to access it through a ref. Using onChangeCapture solved the issue.
1

It works here:

class FileImporter extends React.Component {    
    importFile(e) {
      console.log("fired.");
    }
    render() {
      return (<input type="file" onChange={this.importFile.bind(this)} />);
    }
}

ReactDOM.render(<FileImporter />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

So it must be something else you're doing or some other code. I know this is a different version of React, but it should work the same for you.

1 Comment

I confirmed that your code still works on React 16.3.2, so there were no breaking changes that could be affecting your code. This code works. What does the code inside importFile do? console.log works, have you tried that?
1

For me the problem was, I was selecting the same file again which prevent from triggering the event because I was selecting it in a bootstrap modal where file name was already chosen. So on Closing modal I clear the modal values

e.target.value = null;

This answer might be helpful How to clear input type file values

1 Comment

Using Typescript, I got the error Type 'null' is not assignable to type 'string'. but e.target.value = '' also works
0

It's by design in Chrome. Set value to empty string and store the file in useState() hook or ref.

Comments

0

My issue was that the there was a circular dependency within the state of my input component, input controller & main parent form where I kept track of the state. The logic was valid, but React rerendered the input whenever I selected a file which made me lose access to the onChange event. Spent an hour figuring this out. Ended up using Redux to manage this complex state.

Comments

0

The top answer was the solution for me, just thought i would share code to illustrate the solution. My setup is a 'File' button that produces a drop-down menu, which has 'Load" as one of the options. As this disappears from the DOM the file often wasn't getting loaded. So following the advice from the top comment, i moved it outside of the drop-down menu and instantly fixed the issue:

<div className="toolbar" onMouseLeave={handleMouseLeave}>
  <div className="menu-item">
    <button
      onClick={() => setShowFileDropdown(!showFileDropdown)}
      className={"ml-1"}
    >
      File
    </button>
    {showFileDropdown && (
      <ul className="dropdown">
        <li
          className="dropdown-item"
          onClick={() => {
            newFile();
          }}
        >
          New File
        </li>
        <li
          className="dropdown-item"
          onClick={() => {
            saveToFile();
          }}
        >
          Save
        </li>
        {/* <input
          type="file"
          id="fileInput"
          style={{ display: "none" }}     //<--- MOVE FROM HERE!!!
          onChange={loadFunction}
        /> */}
        <li
          className="dropdown-item"
          onClick={() => {
            document.getElementById("fileInput").click();
          }}
        >
          Load
        </li>
      </ul>
    )}

    <button
      onClick={() => setShowEditDropdown(!showEditDropdown)}
      className={"ml-3"}
    >
      Edit
    </button>
    {showEditDropdown && (
      <ul className="dropdown ml-10">
        <li
          className="dropdown-item"
          onClick={() => {
            dispatch(invertColors());
          }}
        >
          Invert
        </li>
      </ul>
    )}
  </div>
  <input
    type="file"
    id="fileInput"
    style={{ display: "none" }}
    onChange={loadFunction}
  />
</div>

Comments

0

If you are activating a click on the input through a method, remember not to have the onClick attribute on the input, as it will remove the default functionality of the input.

Comments

-6
constructor(props) {
    super(props);
    this.state = {
        value: ''
    }
}
render(){
    return(
       <input type="text" 
              value={this.state.value} 
              onChange={(e) => this.setState({value: e.target.value})}/>
    )
}

1 Comment

The OP is asking why the onChange event isn't firing.

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.