5

I am new to React and trying to build an application where I want to press a custom button which will open a file dialog and upload a file on selecting it. Here is my code:

class ComposeButtons extends Component{

    constructor(props) {
        super(props);
        this.state={
            selectedFile: null
        };
        this.myInput = React.createRef();
    }

    fileSelectedHandler = (event) => {
        console.log(event.target.files[0]);
        this.setState({
            selectedFile: event.target.files[0]
        })
    };
    triggerClick = () => {
        this.myInput.current.click()
    };

    fileUploadHandler = () => {
      /* file upload triggered */
      console.log('file upload triggered');
    };

    render() {
        return(
            <div className={"composeForm-area"}>
                <div>
                    <Input
                        style={{display:'none'}}
                        type={"file"}
                        onChange={this.fileSelectedHandler}
                        ref={this.myInput}
                    />
                    <Button onClick={this.triggerClick}
                            onChange={this.fileUploadHandler} 
                            style={{ backgroundColor: '#DDDCDC'}}>
                        <Icon style={{ fontSize: '20px'}} type="camera" />
                    </Button>
                </div>
            </div>
        )
    }
}
export default ComposeButtons;

My current output:

enter image description here

I only get a clickable icon like above, however, upon clicking it throws:

Uncaught TypeError: _this.myInput.current.click is not a function
    at eval (ComposeButtons.js:88)
    at Button._this.handleClick (button.js:143)
    at HTMLUnknownElement.callCallback (react-dom.development.js:14

What I want:

I simply want to open a file dialog to select file when i click this camera button and after i select and press ok in file dialog, it should close and trigger fileUploadHandler function printing the message on the console. That's all!

What I tried:

Apart from code above I tried to replace code inside div in render method with this code:

        <div>
            <Input
                id="myInput"
                style={{display:'none'}}
                type={"file"}
                onChange={this.fileSelectedHandler}
                ref={(ref) => this.myInput = ref}
            />
            <Button onClick={(e) => this.myInput.click() }
                    style={{ backgroundColor: '#DDDCDC'}}>
                <Icon style={{ fontSize: '20px'}} type="camera" />
            </Button>
        </div>

I also followed almost all the answers on stackoverflow but nothing seems to working for me. It will be really helpful if someone can point me in right direction.

This is my first hobby project in React.

2
  • What exactly is not working? It would be helpful if you put this code on codesandbox for others to tinker with. Commented Aug 20, 2019 at 10:46
  • @MukeshSoni the problem is with the camera button which i have displayed in my question. on clicking it i get an error as shown above, instead it should open a file dialog and when i select a file in it and press ok, dialog should exit triggering fileUploadHandler function which is also mentioned in the question Commented Aug 20, 2019 at 10:56

4 Answers 4

11

As far as I got your question. All we can do is add a label tag referring to the input type file using the for attribute in the label tag. By doing this we don't need to use ref

For info in this link.

Now all that needed to be done is to write appropriate css for the label tag

<div>
  <label htmlFor="myInput"><Icon style={{ fontSize: '20px'}} type="camera" /></label>
  <input
    id="myInput"
    style={{display:'none'}}
    type={"file"}
    onChange={this.fileSelectedHandler}
  />
</div>

After that, to trigger file upload. we can call fileUploadHandler after fileSelectedHandler is called.

fileSelectedHandler = (event) => {
  console.log(event.target.files[0]);
  this.setState({
      selectedFile: event.target.files[0]
  }, () => this.fileUploadHandler());
};
Sign up to request clarification or add additional context in comments.

3 Comments

hi raman, thank you. your code works perfectly fine. It opens a file dialog where i can choose a file, however could you explain after selecting a file from file dialog where exactly can i invoke fileUploadHandler function as shown in my question? in your answer you only trigger fileSelectedHandler function on change
you can call fileUploadHandler after the file change is triggered. I have edited the answer.
thanks for this solution, I wasted many hours in search of this. Now it fully works
0

I would recommend using a library instead of building this yourself. Handle files can be tricky as soon as you want to do just a little more. Try out https://github.com/react-dropzone/react-dropzone. It works great and is simple to use.

2 Comments

@Dhruvify Did you try it out or did you go with your own approach?
I went with the approach mentioned here in the accepted answer above. Works great for me.
0

If you are okay with using hooks there is a package that solves your problem.

https://www.npmjs.com/package/use-file-picker

import { useFilePicker } from 'use-file-picker';

function App() {
  const [filesContent, errors, openFileSelector] = useFilePicker({
    multiple: true,
    accept: '.ics,.pdf',
  });

  if (errors.length > 0) return <p>Error!</p>;

  return (
    <div>
      <button onClick={() => openFileSelector()}>Reopen file selector</button>
      <pre>{JSON.stringify(filesContent)}</pre>
    </div>
  );
}

I created this hook for the same reason as you have.

1 Comment

Hello and welcome to SO! Please read the tour, and How do I write a good answer? Links are great, but showing how whey solve the question is much better.
0

To give a custom image or icon to a input type file, the way i do is :

  1. First create an input tag of input type file.
  2. In css make display as hidden for the input tag type file.
  3. Now put the image you want for the "input type file" in the "img" tag next line.

.input-file{
  display:None;
 }
<input type="file" id="id-input-type" class="input-file"/>
<img src="your-image"/>

  1. Write a function that will be running on click of the "img" tag ( using "onClick" attribute in the img tag ).
  2. The body of this function must be

document.getElementById("id-input-type").click()

Thats it.

I hope i have solved your problem.

Happy coding :)

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.