0

I have two input fields type=file, in a react component. I have to load a json file in each of the input fields and then save the JSON file data in two different variables and update the state of the component. But when I try to do that, both of the file's data get saved in the same variable of state.

Here is the Component

export class comp extends Component {
    constructor(props) {
        super(props);
        this.state = {
            uploadFile1:null,
            uploadFile2:null
        }
        this.readFile1 = this.readFile1.bind(this);
        this.readFile2 = this.readFile2.bind(this);
       
    }
    readFile1(e) {
        var file = document.querySelector("#file");
        if ( /\.(json)$/i.test(file.files[0].name) === false )
        { 
            alert("Not valid JSON file!"); 
        }
        else{
            const fileReader = new FileReader();
            fileReader.readAsText(e.target.files[0], "UTF-8");
            fileReader.onload = e => {
                console.log(e.target.result);
                var data = JSON.parse(e.target.result);
                
                this.setState({
                    uploadFile1: data
                })
            };
            
        }
    }
    readFile2(e) {
        var file = document.querySelector("#file2");
        if ( /\.(json)$/i.test(file.files[0].name) === false )
        { 
            alert("Not valid JSON file!"); 
        }
        else{
            const fileReader = new FileReader();
            fileReader.readAsText(e.target.files[0], "UTF-8");
            fileReader.onload = e => {
                console.log(e.target.result);
                var data = JSON.parse(e.target.result);
                
                this.setState({
                    uploadFile2: data
                })
            };
            
        }
    }
    
    render() {
        return (
            <div className="wrapper">
                
              <input onChange={this.readFile1} type="file" id="file" className="inputfile"/>
              <label htmlFor="file">Browse for files</label>

                            
              <input onChange={this.readFile2} type="file" id="file2" className="inputfile"/>
              <label htmlFor="file">Browse for files</label>
                                
                            
            </div>
        )
    }
}

There are two functions for reading files for both inputs. Although the ids for both the input fields are different but the data gets set in uploadFile1 for both the files.

Is there any problem with the ids of the input field? I cannot change the id of the input filed other than 'file'. If I don't that the above-mentioned problem arise.

2
  • <input onChange={this.readFile} type="file" id="file" className="inputfile"/> Just wondering where your this.readFile is coming from? It's not in the component as far as I can see. Commented Sep 15, 2020 at 8:21
  • Updated the code. It was by mistake over here. Now can you tell me the solution to the stated problem? Commented Sep 15, 2020 at 8:39

1 Answer 1

2

I'm not 100% sure, but I strongly suspect the problem is that you're clicking on your labels, and both labels have htmlFor="file", i.e. both labels point to the first file input.

In addition, your onChange method names are wrong. I guess that's part of inputting the question, but there could be an issue there, it's hard to tell given the code available.

In general, you shouldn't need to use the file ids or querySelector in your onChange methods to get the input values. Instead, you can use e.target to get the changed input directly. Using that you could reduce your code down to a single readFile method that can handle either input, which might make this easier to manage. Something like this:

onFileChanged(changeEvt) {
    const file = changeEvt.target;
    const fileId = file.id;

    if (/\.(json)$/i.test(file.files[0].name) === false) {
        alert("Not valid JSON file!");
    } else {
        const fileReader = new FileReader();
        fileReader.readAsText(file.files[0], "UTF-8");

        fileReader.onload = () => {
            console.log(fileReader.result);
            const data = JSON.parse(fileReader.result);

            this.setState({
                ['upload-' + fileId]: data
            })
        };
    }
}

render() {
    return (
        <div className="wrapper">
            <input onChange={this.onFileChanged} type="file" id="file1" className="inputfile"/>
            <label htmlFor="file1">Browse for files</label>

            <input onChange={this.onFileChanged} type="file" id="file2" className="inputfile"/>
            <label htmlFor="file2">Browse for files</label>
        </div>
    )
}

I haven't properly tested that, but you get the idea. Note that I'm using a computed property name in the setState, so you'll need to be in an environment (i.e. modern browser) where that's supported.

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

2 Comments

Can you show me an example code for doing the same thing with e.target instead of onChange function, please?
@AyeshaYounis Great! Once an answer solves your problem, you should accept it (click the ✓) so that everybody knows this question is resolved

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.