React - input type file Semantic UI React
Asked Answered
A

5

17

I'm trying to implement a file upload, but using SUIR <Input>, button, label, etc.

This is strictly about the use of the elements in render.

Using regular html <label> and <input> elements this process works as expected.

  <Form.Field>
    <label>File input & upload for dataschemas & datasources</label>
    <input type="file" onChange={this.fileChange} />
    <Button type="submit">Upload</Button>
  </Form.Field>

Now I'm trying to use SUIR <Input> element, as well as some props with the <Button> element for styling.

  <Form.Field>
    <label>File input & upload </label>
    <Input type="file" onChange={this.fileChange}>
      <Button
        content="Choose File"
        labelPosition="left"
        icon="file"
      />
    </Input>
    <Button type="submit">Upload</Button>
  </Form.Field>

You can visit the codesandbox here to get a better visual idea of what I'm talking about.

When I click Choose File in the SUIR implementation example it does not prompt the user to chose a file from their system, whereas the regular html <input> does. I'm not sure how to get <Input type="file ...> in semantic to behave the same way.

Antiphonal answered 1/4, 2019 at 22:8 Comment(0)
P
31

SUIR doesn't provide a FileInput button solution out of the box. But you can easily create your own implementation of such button. For instance, usually this is done by using a hidden file input and a button which triggers the hidden input click when user clicks on it:

  <Button
    content="Choose File"
    labelPosition="left"
    icon="file"
    onClick={() => this.fileInputRef.current.click()}
  />
  <input
    ref={this.fileInputRef}
    type="file"
    hidden
    onChange={this.fileChange}
  />

Where this.fileInputRef is a React ref created by React.createRef() method. You can check this codesandbox example with the above solution.

Poplar answered 2/4, 2019 at 1:6 Comment(1)
if using hooks, you'll want to use useRef. import React, { useRef } from 'react'Xenophobe
A
12

The answer by GProst works perfectly well. In another case you might not want to create a ref to achieve this file input button.

The solution below uses the htmlFor prop and passes that id to the <input>. Not using ref eliminates extra JS, and unnecessary communication between button and input.

<Button as="label" htmlFor="file" type="button">
  Some button stuff
</Button>
<input type="file" id="file" style={{ display: "hidden" }} onChange={this.onChange} />
Antiphonal answered 2/4, 2019 at 15:11 Comment(5)
Much better and intuitive, should be the accepted answerInlay
This solution doesn't work if you're building a component which might have multiple instances on the document. You should always defer DOM state management to React wherever you can, so the solution posed by GProst is a better answer.Xenophobe
don't use id's in react! Use refs insteadBrigitte
"don't use id's in react" sound good, but why not?Kuhlman
visibility: 'hidden' for some new browsersUnthinkable
T
6

You can setup file upload form with react as below.

And also you can get the filename and the reference of the file as demonstrated in this example, I have included the front end upload logic with axios and the backend code if you are using express, node stack

class Thingy extends React.Component {
  
  uploadFile = event => {
    
    // filename
    console.log('filename ' + event.target.value);
    
    //file 
    console.log('file ' + event.target.files[0]);
    
    // if you are using axios then you can use below code
    //const formData = new FormData();
        // formData.append('file', event.target.files[0])
        // axios.put(
        //     'url',
        //     formData,
        //     { headers: { 'content-type': 'multipart/form-data' } }
        // ).then(data => {
        //     console.log('file uploaded')
        //     console.log(data)
        // }).catch(e => {
        //     console.log('error')
        //     console.log(e)
        // })
        
        // in express , node, backend code would be
        //import formidable from 'formidable'
        //(req, res) => {
        //  let form = new formidable.IncomingForm();
        //  form.parse(req, (err, fields, files) => {
            // you can get the file from files.file.path
        //  })
        // }
  }
  
  render() {
    console.log("rendered");
    return (
      <div>
        <input type="file" id="file" name="filename" onChange={this.uploadFile} />
      </div>
    );
  }
}

// Render it
ReactDOM.render(
  <Thingy/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Tsana answered 24/8, 2019 at 8:33 Comment(3)
This is the more react way of doing this. The accepted answer uses refs which should be avoided when possible. Refs are to be used when manual control of a certain component that is needed, such as a custom component with it's own API imported from a libraryBeating
I had taken the accepted answer and altered it to not use refs. I did not want to give myself the accepted answer even though it's better to not use refs in this situation, as denoted in my answer. And originally this question was more geared towards how to get the <Input> element from SUIR to play nicely with file input.Antiphonal
The codesandbox I posted in the question handles the event in just this way.Antiphonal
F
2

This is my solution:

         function mainPage(){
            const [newFile, SetNewFile] = useState([]); 

            const fileChange = (event) => {
                SetNewFile( event.target.files[0] );
             };

            const onFormSubmit = () =>{
              // Do something
            }

            return(
            <Form onSubmit={onFormSubmit}>
                <Form.Field>
                    <Button as="label" htmlFor="file" type="button">
                        Some button stuff
                    </Button>
                    <input type="file" id="file" hidden onChange={fileChange} />

                </Form.Field>
                <Button type="submit">Upload</Button>
            </Form>)
            }
Foible answered 14/5, 2020 at 16:23 Comment(0)
D
0

Using only the react-semantic-ui's Input props. Following @GProst and @DJ2 answers, you can do something like:

<Input
  action={{
    icon: 'upload',
    className: 'file-button-provider-icon', //<-- your css
    onClick: () => document.querySelector('#file-input-button').click()
  }}
  input={{
    id: 'file-input-button',
    hidden: true,
  }}
  onChange={fileChange}
  type='file'
/>

enter image description here

Dewaynedewberry answered 1/12, 2023 at 12:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.