PapaParse returns undefined when reading CSV
Asked Answered
B

4

7

My goal is to open a CSV file, then parse its contents onto a <div> using PapaParse. So far it seems to be working but instead of actual values it just returns undefined. I have no idea what's wrong, could be a strange CSV file (I made this from an excel table with Save As), or it could just be sloppy coding.

JS

var data;

function handleFileSelect(evt) {
    var file = evt.target.files[0];

    Papa.parse(file, {
        header: true,
        dynamicTyping: true,
        complete: function (results) {
            data = results;
        }
    });
    $(".graphcontainer").append("<div class='parse'>" + data + "</div>");
}

$(document).ready(function () {
    $("#csv-file").change(handleFileSelect);
});

HTML

<div class="graphcontainer">Parser Output:</div>
<div class="buttoncontainer">
    <input type="file" id="csv-file" name="files"/>
</div>

edit: here are the files I've been testing with (http://www.topdeckandwreck.com/excel%20graphs/). Don't know if this is really relevant as the goal of this is for the user to be able to open any CSV file and then making a graph out of it :)

Biagio answered 2/1, 2015 at 11:24 Comment(2)
after trying it out with different CSV files it just returns [Object object]Justifier
You might want to add the CSV files you are using to your question.Eous
E
17

You very likely have a timing problem.

Papa is an asynchronous library, a telltale sign is the fact that is offers a complete callback.

That means you can't use a global variable to transfer its results from A to B. In fact, you should avoid global variables in general.

All work you want to be done after the result is ready must be done in the callback function. This applies to any asynchronous process in JavaScript.

function handleFileSelect(evt) {
    if ( !(evt.target && evt.target.files && evt.target.files[0]) ) {
        return;
    }    
    Papa.parse(evt.target.files[0], {
        header: true,
        dynamicTyping: true,
        complete: function (results) {
            debugDataset(results);
            renderDataset(results);
        }
    });
}

function debugDataset(dataset) {
    var formatted = JSON.stringify(dataset, null, 2);
    $("<div class='parse'></div>").text(formatted).appendTo(".graphcontainer");
}

function renderDataset(dataset) {
    // render code here...
}

$(function () {
    $("#csv-file").change(handleFileSelect);
});
Eous answered 2/1, 2015 at 14:39 Comment(4)
thing is, I want to be able to use the variable in a function from another library that makes graphs out of 2 values (x, y) so I thought it would be better if I just made a global variable in order to play with it further along. Here I'm just outputting it on a div to see what's going on (for some reason F12 doesn't show anything in console). the result is still the same, only it now outputs [object Object] on all my filesJustifier
No, you can't use a global variable since you don't know when that global variable is going to be set. You must do all result processing inside the callback. Hint: When you call functions from that callback, you are technically still inside the callback. You don't have to cram all code into that one function, you just have to trigger all processing from it.Eous
the parser still just outputs [object Object] instead of the actual data, no matter what CSV file I use (tried making some with a random online generator).Justifier
@Miha Of course, if the results are an object (and they are!) then JavaScript displays [object Object] because that's the default textual representation of objects. If you want to display something else (like a JSON representation) you must create that first. See modified answer.Eous
S
1

I think you want to see the results when it's actually completed:

function handleFileSelect(evt) {
    var file = evt.target.files[0];

    Papa.parse(file, {
        header: true,
        dynamicTyping: true,
        complete: function (results) {
            var data = results;
            $(".graphcontainer").append("<div class='parse'>" + data + "</div>");
        }
    });
}
Swat answered 2/1, 2015 at 14:49 Comment(2)
That's kind of exactly what my answer says... ;)Eous
Hum for some reason I haven't noticed it :-PSwat
S
1

You can also use a promise to retreive the result.

async getData() {
    return await new Promise((resolve, reject) => {
        try {
            Papa.parse(
                `${ window.location.protocol }//${ window.location.host }/data/myfile.csv`, 
                {
                    download: true,
                    worker: true,
                    header: true,
                    complete: function(r) {
                        resolve(r.data);
                    }
                }
            )
        }
        catch (e) {
            reject(e);
        }
    });
}
Sedate answered 16/2, 2022 at 10:13 Comment(0)
B
0

ok so I solved the problem, the solution is this (var needs to contain results.data)

{

function handleFileSelect(evt) {
    var file = evt.target.files[0];

    Papa.parse(file, {
        complete: function (results) {
            var data = results.data;
            $(".graphcontainer").append("<div class='parse'>" + data + "</div>");
        }
    });
}

$(function () {
    $("#csv-file").change(handleFileSelect);
});

}

thanks for the help from the others

Biagio answered 2/1, 2015 at 15:19 Comment(1)
Hint: If your code isn't self-contained and executable, just use the "{} (Code Sample)" button instead of the "Code Snippet" button. This way you prevent the creation of a non-functional "Run code snippet" button in your answer.Eous

© 2022 - 2024 — McMap. All rights reserved.