-1

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>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
Tony
  • 469
  • 1
  • 6
  • 18
  • `how the heck I should know that FilreRead() is async` - well, the first line of the documentation is: *The FileReader object lets web applications **asynchronously** read the contents of files* .... 1. `Which part of your 5000 word general answer` - the part that applies to your code .... 3. `Guys like you make StackOverflow not a friendly place for novice programmers.` - you've been a member for 7 years ... so, you're not a novice :p – Jaromanda X Oct 15 '20 at 05:49
  • your function `fileToArray` can't *return* the contents, but, by adding a callback argument you can call a function where you call `console.log(csvArray);` - and that's where the contents is available – Jaromanda X Oct 15 '20 at 05:50
  • `const fileinput = document.querySelector("#csvfile").files[0]` is too early. You need `const fileinput = document.querySelector("#csvfile");`and then later on click use `fileinput.files[0]` – mplungjan Oct 15 '20 at 06:03
  • @JaromandaX, I know. The question was closed for a reason and there is no justification wrt SO's policies to repost the same question. This should be closed and deleted. The OP can improve their first question if they think the duplicate doesn't answer their question – Vega Oct 15 '20 at 06:10

1 Answers1

1

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);
    });
};
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Btw, you are JS gold badge holder. If you consider that the original was wrongly closed, you can one-handly re-open and answer on that, close/delete vote this one, instead of encouraging of reposting questions, which is really bad – Vega Oct 15 '20 at 10:15
  • I had no idea I could do that @Vega – Jaromanda X Oct 15 '20 at 10:16
  • @JaromandaX So as far as I understand, what makes the function asynchronus is the .onload method. And the way to return in the async functions is the callback which works somehow like the return. Am I getting it correctly? Also, why you use promise on the second way? Isnt supposed that the asynchronus .onload method would return a promise anyway? – Tony Oct 15 '20 at 19:43
  • no, asynchrony has been a part of javascript forever, Promises are a relatively new way of dealing with asynchrony - the main claim to fame for Promises is overcoming callback hell / pyramid of doom by allowing you to chain asynchronous tasks rather than nest them – Jaromanda X Oct 15 '20 at 21:43