DJ2
DJ2

Reputation: 1741

React - input type file Semantic UI React

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.

Upvotes: 17

Views: 23624

Answers (5)

Juninho De Luca
Juninho De Luca

Reputation: 85

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

Upvotes: 0

meck373
meck373

Reputation: 1124

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>)
            }

Upvotes: 2

noone
noone

Reputation: 6558

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>

Upvotes: 6

DJ2
DJ2

Reputation: 1741

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} />

Upvotes: 12

GProst
GProst

Reputation: 10227

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.

Upvotes: 31

Related Questions