Yarin Nim
Yarin Nim

Reputation: 3817

How to trigger INPUT FILE event REACTJS by another DOM

I have a INPUT BUTTON and INPUT FILE, I want to click the BUTTON and it will trigger the INPUT FILE event in REACT JS.

React.createElement('input',{type:'file', name:'myfile'})

then the button

React.createElement('a',{onClick: this.doClick},'Select File')

So how to define and trigger the INPUT FILE click event when we click the A HREF?

Your help is appreciate. :-)

Upvotes: 34

Views: 56015

Answers (9)

Patrick Chua
Patrick Chua

Reputation: 31

For those who want to implement Farid's answer in Typescript, can do the following:

import React, {useRef} from 'react';
const FancyInput = () => {
  const fileInput = useRef<HTMLInputElement>(null)

  const handleClick = () => {
    if(fileInput.current) {
      fileInput.current.click()
    }
  }

  const handleFileChange = event => {
      console.log("Make something")
  }

  return(
      <div className="patientactions-container">
          <input
              type="file"
              onChange={(e) => handleFileChange(e)}
              ref={fileInput} 
          />
          <div onClick={() => handleClick()}></div>
      </div>
  )
}
export default FancyInput;

Upvotes: 3

Hypermona
Hypermona

Reputation: 147

Anyone Looking for a Simple approach try this.

<div>
  <input type="file" name="library-images" id="library-images" hidden />
     <Button type='button' onClick={()=>{
                document.getElementById("library-images")?.click()
     }}>Upload</Button>
</div>

Upvotes: 2

Admond Tamang
Admond Tamang

Reputation: 21

const CustomInput = () => {
  const handleClick = () => {
    document.getElementById("file_upload").click();
  };

  const handleFileChange = (event) => {
    console.log("Make something");
  };

  return (
    <div className="patientactions-container">
      <input type="file" id="file_upload" onChange={(e) => handleFileChange(e)} />
      <div onClick={() => handleClick()}></div>
    </div>
  );
};
export default CustomInput;

Upvotes: 0

Yogi
Yogi

Reputation: 1722

Update: Sep 18, 2021

Note: On NextJS, I was facing onChange event is not trigged from input file element. For that, we can use onInputCapture or onChangeCapture. For more detailed information, Stackoverflow - onChange event is not firing

Basic example on onChangeCapture as per our requirement. Requires React ^16.8,

const Dummy = () => {
  const inputFileRef = React.useRef();
  const onFileChangeCapture = ( e: React.ChangeEvent<HTMLInputElement> ) {
    /*Selected files data can be collected here.*/
    console.log(e.target.files);
  };
  const onBtnClick = () => {
    /*Collecting node-element and performing click*/
    inputFileRef.current.click();
  };
  return (
    <form>
      <input
        type="file"
        ref={inputFileRef}
        onChangeCapture={onFileChangeCapture}
      />
      <button onClick={onBtnClick}>Select file</button>
    </form>
  );
};

Using useRef Hook in functional components. Requires React ^16.8,

const Dummy = () => {
  const inputFileRef = useRef( null );

  const onFilechange = ( e ) => {
    /*Selected files data can be collected here.*/
    console.log( e.target.files );
  }
  const onBtnClick = () => {
    /*Collecting node-element and performing click*/
    inputFileRef.current.click();
  }

  return (
    <form className="some-container">
      <input
        type="file"
        ref={inputFileRef}
        onChange={onFileChange}
      />
      <button onClick={onBtnClick}>Select file</button>
    </form>
  )
}

Class Implementation with React.createRef() and handling click with node element.

class Dummy extends React.Component {
    
  constructor( props ) {
    super( props );

    this.inputFileRef = React.createRef();
    this.onFileChange = this.handleFileChange.bind( this );
    this.onBtnClick = this.handleBtnClick.bind( this );
  }

  handleFileChange( e ) {
    /*Selected files data can be collected here.*/
    console.log( e.target.files );
  }

  handleBtnClick() {
    /*Collecting node-element and performing click*/
    this.inputFileRef.current.click();
  }

  render() {
    return (
      <form className="some-container">
        <input
          type="file"
          ref={this.inputFileRef}
          onChange={this.onFileChange}
        />
        <button onClick={this.onBtnClick}>Select file</button>
      </form>
    )
  }
}

Upvotes: 66

Fran&#231;ois Richard
Fran&#231;ois Richard

Reputation: 7045

EDIT: This is a question I answered a long time ago not knowing very much react at this time. The fun thing is that it has been considered valid ^^.

So for anyone reading this answer; this answer is wrong and is a very good example of something you shouldn't do in react.

Please find below a nice anti-pattern, again, don't do it.

=================================================

You can achieve this using jQuery:

this.doClick: function() {
    $('input[type=file]').trigger('click');
}

React does not provide specific functions to trigger events, you can use jQuery or simply native Javascript: see Creating and triggering events on MDN

Upvotes: -24

Michael Osofsky
Michael Osofsky

Reputation: 13155

Building on the answer from @YÒGÎ , here is an implementation using TypeScript:

class Dummy extends React.Component {
    fileInputRef: React.RefObject<HTMLInputElement> = React.createRef();

    forwardClickToInputElement = () => {
        this.fileInputRef.current!.click();
    };

    handleUploadDemand = (ie: ChangeEvent<HTMLInputElement>) => {
        const fileList: FileList = ie.target.files;

        // do something with the FileList, for example:
        const fileReader = new FileReader();
        fileReader.onload = () => {
            const str = String(fileReader.result);
            try {
                const parsedContent = YOUR_OWN_PARSING(str);
            } catch (error) {
                // YOUR OWN ERROR HANDLING
            }
        };
        fileReader.readAsBinaryString(fileList[0])
    }

    render() {
        return (
            <div className="some-container">
                <button onClick={this.forwardClickToInputElement}>Select File</button>
                <input ref={this.fileInputRef} type="file" onChange={this.handleSelectFile} hidden={true}/>
            </div>
        )
    }
}

References:

  1. Solution for how to use refs in React with Typescript https://stackoverflow.com/a/50505931/2848676
  2. Use ! operator for ref type narrowing https://medium.com/@martin_hotell/react-refs-with-typescript-a32d56c4d315

Upvotes: 4

Farid Murzone
Farid Murzone

Reputation: 136

Using Hooks with useref:

import React, {useRef} from 'react';
const FancyInput = () => {
    const fileInput = useRef(null)

    const handleClick = () => {
        fileInput.current.click()
    }

    const handleFileChange = event => {
        console.log("Make something")
    }

    return(
        <div className="patientactions-container">
            <input
                type="file"
                onChange={(e) => handleFileChange(e)}
                ref={fileInput} 
            />
            <div onClick={() => handleClick()}></div>
        </div>
    )
}
export default FancyInput;

Upvotes: 7

Fidel Ramadhan
Fidel Ramadhan

Reputation: 411

You could trigger the input type file with ref, f.e:

on your class component:

<input 
    ref={fileInput => this.fileInput = fileInput} 
    type="file"
 />
<button onClick={this.triggerInputFile}> Select File </button>

and make a function on that class component too:

triggerInputFile = () => this.fileInput.click()

Upvotes: 35

Bart S
Bart S

Reputation: 1808

You don't need jQuery for this. You don't even need an event handler. HTML has a specific element for this, called label.

First, make sure your input element has an id attribute:

React.createElement('input',{type:'file', name:'myfile', id:'myfile'})

Then, instead of:

React.createElement('a',{onClick: this.doClick},'Select File')

Try:

React.createElement('label',{htmlFor: 'myfile'},'Select File')

(Instead of adding htmlFor and id attributes, another solution is to make the input element a child of the label.)

Now clicking the label should trigger the same behaviour as clicking the input itself.

Upvotes: 40

Related Questions