[SalesForce] how to convert CSV file to array of JS objects in LWC

I have a custom LWC page where I am importing an array of JS object to CSV and it is working as expected now I need to do some changes to that csv file and upload it on the page and convert it back to an array of JS object.

I have tried to use the below code

HTML:

<lightning-file-upload name="fileUploader" accept={acceptedFormats} record-id={productconfigid}
                    onuploadfinished={handleUploadFinished}>
</lightning-file-upload>

JS:

 handleUploadFinished(event) {
        // Get the list of uploaded files
        const uploadedFiles = event.detail.files;
        console.log(uploadedFiles);
        alert("No. of files uploaded : " + uploadedFiles.length);
    }

The above doesn't work because I am using my LWC component from lighting out and as per the documentation upload file would be disabled in lightning out but in my case it is not disabled upon clicking upload files it opens a pop up to upload a file and when I select the file nothing happens, no alert no console logs.

other then above I have tried custom html element to do the same.

HTML:

<form id='importPfForm'>
         <input type='file' name='datafile' id="input">
         <input type='button' value='IMPORT' onclick={handleUploadFinished} />
   </form>

JS:

    handleUploadFinished(event) {

            const uploadedFiles = this.template.querySelector('input').files[0];
            console.log(uploadedFiles ); 
   }

console log prints below information regarding the uploaded file

File {name: "uploadedFile.csv", lastModified: 1587959237199,
lastModifiedDate: Mon Apr 27 2020 09:17:17 GMT+0530 (India Standard
Time), webkitRelativePath: "", size: 4995, …}

if I change my JS to below to read the data from file

handleUploadFinished() {

    this.template.querySelector('input[type="file"]')
        .addEventListener('change', function () {
            var files = this.files;

            for (var i = 0; i < files.length; i++) {
                parseCSV(files[i], ',', function (result) {
                    console.log(result);
                });
            }
        })
}

parseCSV(file, delimiter, callback) {
    var reader = new FileReader();

    // When the FileReader has loaded the file...
    reader.onload = function () {

        // Split the result to an array of lines
        var lines = this.result.split('\n');

        // Split the lines themselves by the specified
        // delimiter, such as a comma
        var result = lines.map(function (line) {
            return line.split(delimiter);
        });

        // As the FileReader reads asynchronously,
        // we can't just return the result; instead,
        // we're passing it to a callback function
        callback(result);
    }

    // Read the file content as a single string
    reader.readAsText(file);
}

upon clicking the import button nothing happens, no console log nothing, it doesn't execute code inside the addEventListner method but the above code is working as expected in this [JS Fiddle][1]

can someone please suggest why the same is not working in LWC?

UPDATE:

Code mentioned by sfdcfox is working as expected but the only problem is when when one of the row values have special character then it doesn't parse csv as expected for example

srNumber, names
1,john doe
2,Frank
3,vito
4,Tom, hagen

up to first 3 line it will work as expected but on 4th line name Tom, hagen has comma in it which creates problems while reading the content.

Best Answer

You're adding a handler to the input element to fire when a change occurs, but you've already selected the file and clicked the import button. So, it would wait until the next change before that happens. Instead, just go ahead and read the files.

Here's a simple demonstration:

import { LightningElement, track, api } from 'lwc';

export default class App extends LightningElement {
    readFiles() {
        [...this.template
            .querySelector('input[type="file"]')
            .files].forEach(async file => {
                try {
                    const result = await this.load(file);
                    // Process the CSV here
                    console.log(result);
                } catch(e) {
                    // handle file load exception
                }
            });
    }
    async load(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = function() {
                resolve(reader.result);
            };
            reader.onerror = function() {
                reject(reader.error);
            };
            reader.readAsText(file);
        });
    }
}

<template>
    <input type="file" multiple accept=".csv"/>
    <button onclick={readFiles}>Import</button>
</template>