Search code examples
javascriptarraysexceljs

Javascript array contents disappear after leaving function context


I'm using the Node npm library "ExcelJS" to read in an Excel workbook's worksheet and populate an array with objects that represent the data found in the sheet's rows.

I don't believe the issue is directly related to ExcelJS, rather probably due to my fundamental lack of understanding of Javascript function context.

The code:

getData = function () {
    var dataRows = [];

    workbook.xlsx.readFile("myExcelWorkbook").then(function () {
        var worksheet = workbook.getWorksheet("MyWorksheet");

        worksheet.eachRow(function (row) {
            var dataRow = {
                colA: row.getCell("A").value,
                colB: row.getCell("B").value,
                colC: row.getCell("C").value
            };

            dataRows.push(dataRow);
        });
    });

    return dataRows;
};

If I debug step through the above code I can see where the dataRows object IS being populated with the correct data found during the eachRow function. However, once exiting the "readFile" function, all items populated into the dataRows object simply disappear.

No matter how I attempt to populate dataRows (e.g. calling an outer function to populate the dataRows array), any object created within the context of the workbook.xslx.readFile() appears to be destroyed afterwards. Weird.


Solution

  • workbook.xlsx.readFile is an async function. You are returning dataRows before the async is executing.

    See How do I return the response from an asynchronous call?

    Following is a simple way to fix this using a callback. Pass the function that expects dataRows output to getData, and then call it once dataRows is built. Again, there are better solutions using promises explained in the linked question.

    getData = function (callback) {
        var dataRows = [];
    
        workbook.xlsx.readFile("myExcelWorkbook").then(function () {
            var worksheet = workbook.getWorksheet("MyWorksheet");
    
            worksheet.eachRow(function (row) {
                var dataRow = {
                    colA: row.getCell("A").value,
                    colB: row.getCell("B").value,
                    colC: row.getCell("C").value
                };
    
                dataRows.push(dataRow);
            });
    
            callback(dataRows);
        });
    
        return dataRows;
    };