Search code examples
javascriptfilereader

Returning results from FileReader()?


I am trying to make a simple csv to JSON converter (just to practice) but I haven't found any way to grab the data from the FileReader() function with a return. I don't know if this is even possible.

So what the code below does: it just grabs a csv file and after pressing the button to it tries to run a function that converts it to an array (so far). What prints the array is the console.log which works ok but what if I wanted to return this array so I can pass it to another function? Whenever I use return csvArray; and then instead of running the function trying to console.log(fileToArray(fileinput)); I get undefined. I haven't found anything online regarding this that uses vanilla JS.

const fileinput = document.querySelector("#csvfile").files[0];
const convertBtnFile = document.querySelector("#convertBtn");

convertBtnFile.addEventListener("click", (e) => {
  e.preventDefault();
  fileToArray(fileinput);
});

const fileToArray = (csvFile) => {
  const myFile = new FileReader();
  myFile.onload = (event) => {
    const wholeText = event.target.result;
    const splitLines = wholeText.split(/\r\n|\n/);
    csvArray = splitLines.map(i => i.split(","));
    console.log(csvArray);
  }
  myFile.readAsText(csvFile);
}
<input type="file" id="csvfile" /><br/> <button type="button" id="convertBtn">Convert</button>


Solution

  • One thing your code does wrong is

    const fileinput = document.querySelector("#csvfile").files[0];
    

    straight away - you want to wait until you're in the click handler before you try to read the file

    The simplest answer for you is to use a callback in fileToArray function

    const convertBtnFile = document.querySelector("#convertBtn");
    
    convertBtnFile.addEventListener("click", (e) => {
        e.preventDefault();
        const fileinput = document.querySelector("#csvfile").files[0];
        fileToArray(fileinput, data => {
            // do things with results here *********
        });
    });
    
    const fileToArray = (csvFile, cb) => { // ********
        const myFile = new FileReader();
        myFile.onload = (event) => {
            const wholeText = event.target.result;
            const splitLines = wholeText.split(/\r\n|\n/);
            csvArray = splitLines.map(i => i.split(","));
            cb(csvArray); // **** call the supplied function with the results
        }
        myFile.readAsText(csvFile);
    }
    

    If you're comfortable with async/await, you can do this - the benefit is, it "looks" synchronous

    const convertBtnFile = document.querySelector("#convertBtn");
    
    //                                 note: vvvvv async
    convertBtnFile.addEventListener("click", async (e) => {
        e.preventDefault();
        const fileinput = document.querySelector("#csvfile").files[0];
        const data = await fileToArray(fileinput);
        // do things here
    });
    
    const fileToArray = csvFile => {
        return new Promise((resolve, reject) => {
            const myFile = new FileReader();
            myFile.onload = event => {
                const wholeText = event.target.result;
                const splitLines = wholeText.split(/\r\n|\n/);
                csvArray = splitLines.map(i => i.split(","));
                resolve(csvArray);
            }
            myFile.onerror = reject;
            myFile.readAsText(csvFile);
        });
    };