[SOLVED] List with rows cannot be accessed by common JS syntax; '.data'

I am not able to access the ‘.data’ functionality from common JS. Cf this source’ example (40% down @ “There you go:”). I have rewritten the example into this:

var Gpuperf = pc.createScript('gpuperf');

// initialize code called once per entity
Gpuperf.prototype.initialize = function() {
    this.t0 = performance.now(); this.fr =0; this.deltaT50 =0; deltaT_Total = 0; this.fr_Total =1; 
    this.rows = []; 
    this.app.mouse.on(pc.EVENT_MOUSEWHEEL, this.onMouseWheel, this);
};

// update code called every frame
Gpuperf.prototype.update = function(dt) {
    //var txtP = this.app.root.findByName("TextPerf");
    var t1 = performance.now(); var t1DatapointIdx =0; var t1UsableVaue = (t1*1000).toFixed(2);  var deltaT =0; deltaT+= dt; 
    
    try{
        if(this.entity.animation.currentTime < this.entity.animation.duration) {
        // Animation is running:
        if(this.fr > 50) {this.deltaT50=deltaT/50*1000; this.fr =0; deltaT_Total = this.deltaT50/this.fr_Total*1000;
        var perfPrScrRes =0; var h = window.innerHeight; var w = window.innerWidth; perfPrScrRes = this.deltaT50/(Math.sqrt(h*w)/1000)*1000;
        this.app.root.findByName("TextPerf").element.text = "GPU scr P: "+perfPrScrRes.toFixed(3) + ":"+this.deltaT50.toFixed(3); var t1GetAnimTime = (t1 - this.t0)/1000;

        this.rows.push([t1DatapointIdx, t1UsableVaue, perfPrScrRes, t1GetAnimTime]); t1DatapointIdx++; console.log("TRL: "+ this.rows.length);
       }
    } else {   
        var tmpGetAnimTime = (t1 - this.t0)/1000;
        if(this.fr >3){this.app.root.findByName("TextPerf_AnimDone").element.text = tmpGetAnimTime.toFixed(2);}
        if(this.fr > 50) {
            this.fr =0;}
    }
    } catch(err){}
    this.fr++; this.fr_Total++;
};

Gpuperf.prototype.onMouseWheel = function(event){

    console.log("onMouseWheel " + this.rows.length +" :: "+ this.rows[1]);

        var result; var ctr; var keys; var columnDelimiter; var lineDelimiter; var data;

        data = this.rows.data || null;
        if (data === null || !data.length) {
            console.log("onMouseWheel null" ); // NB! This is where the whole script returns (stops) 
            return null;
        }

        columnDelimiter = this.rows.columnDelimiter || ',';
        lineDelimiter = this.rows.lineDelimiter || '\n';
console.log("onMouseWheel tr2" );
        keys = Object.keys(data[0]);

        result = '';
        result += keys.join(columnDelimiter);
        result += lineDelimiter;
console.log("onMouseWheel tr3" );
        data.forEach(function(item) {
            ctr = 0;
            keys.forEach(function(key) {
                if (ctr > 0) result += columnDelimiter;

                result += item[key];
                ctr++;
            });
            result += lineDelimiter;
        });
console.log("onMouseWheel  tr4" );
this.downloadCSV("stock-data.csv");

};

Gpuperf.prototype.downloadCSV = function(filename) {
        var data,  link;

        var csv = convertArrayOfObjectsToCSV({
            data: this.rows
        });
        if (csv === null) return;

        filename = this.rows.filename || 'download';

        if (!csv.match(/^data:text\/csv/i)) {
            csv = 'data:text/csv;charset=utf-8,' + csv;
        }
        data = encodeURI(csv);   console.log("DWL data  " + data );

        link = document.createElement('a');
        link.setAttribute('href', data);
        link.setAttribute('download', filename);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
       };

What to put instead at this.rows .data in order to get past the ‘if (data === null || !data.length) {’-condition?

Hi @Thomas_Due_Nielsen,

From what I see this.rows is an array, so you have to access each row using its numeric index:

this.rows[0].[properyName];

// e.g. this.rows[0].name; 
// if the body includes a name property

That will access the first element (row).

Yes, but the access to the array-index is not where the script ‘fails’.
At the place where the ‘data’ is written by ‘this.rows.data’:

data = this.rows.data || null;

  • the result tilts past the ‘||’-part; equalling ‘null’
    Therefore the script halts at ‘return null;’

As ‘PC-JS’ is ‘close to’ but not entirely ‘common JS’, I am looking for the PC-JS variant of ‘.data’ as in 'this.rows.data ’ above? :slight_smile:

There is no .data property in the this.rows property since it’s an array.

There is a .length property so if you would like to check if the array is populated with items, you can do this:

data = this.rows.length > 0 || null;
1 Like

this.rows is an array. JS arrays have no property called data therefore it is undefined.

PlayCanvas JS is just normal, vanilla JS (ES5). You’ve brought this up before but I still don’t understand where this notion has come from.

ok, get that ‘PC-JS’ === vanilla JS (ES5) - still doesn’t change that a ‘common JS (of 2018)’ stackoverflow-community regards the usage of a ‘.data’-containing example by grading it; “Awesome answer. I’m upvoting this one … etc”. … Just saying … :thinking:

We are back at the fact that ‘.data’ (apparently) doesn’t work in PC => vanilla JS (ES5).
So I guess I can move on in the debugging of the script :slight_smile: , by passing the part of:

 data = this.rows.data || null;
        if (data === null || !data.length) {
            console.log("onMouseWheel null" ); // NB! This is where the whole script returns (stops) 
            return null;
        }

Then I get down to the parts of:

        keys = Object.keys(data[0]);

        result = '';
        result += keys.join(columnDelimiter);
        result += lineDelimiter;
console.log("onMouseWheel tr3" );
        data.forEach(function(item) {
  • where access of ‘data’ is needed anyway.
    As such; a method to use the ‘.data’-functionality (or equal to) alongside the list/array of this.rows[i].
    {data = this.rows.data}

I am not sure you understood correctly what @yaustar and @Leonidas are saying. In javascript Array types do not have .data property. You cannot access this.rows.data - it simply doesn’t exist. It has nothing to do with Playcanvas.

1 Like

Can you show us the example from Stackoverflow that you are getting this data property from please?

Ok, let us turn the whole thing upside down and forget versions and parallel JS-communities. If a Stackoverflow example of 2018 does not comply with present PlayCanvas, then what to use in order to write to a .csv-file and save it? (being my main goal)
I have already tried out 3-4 of the examples in the stackoverflow example, without luck (and mainly due to JS-versions/age of the early examples (6-9 years old)).

I’m assuming this is the Stackoverflow answer you are using? https://stackoverflow.com/questions/44440208/how-to-remove-the-when-converting-javascript-object-to-csv-file/44440316

If so, the function converts an array of objects to a CSV file. The args function param is an object that has .data as the array as well as other properties.

Example project using the StackOverflow answer above: https://playcanvas.com/editor/scene/924158

Prints:

name,phone
"steven","0000000"
"foo","111111"
"bar","222222"
1 Like

The ressource was/is: https://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side

  • but still relevant in regards to the usage of ‘args’.
    (I haven’t used the ‘args’-approach so much in general - will get back later)

It’s a custom object they are passing as arguments to a function:

myFunction({ 
  filename: 'filename.csv',
  data: [1, 2, 3],
  columns: [a, b],
  myOtherCustomProperty: [4, 5, 6]
});

myFuction = function (options) {
   console.log( options.data )            // [1, 2, 3]
   console.log( options.myOtherCustomProperty )    // [4, 5, 6]
}

As you can see, .data is something they came up with as a name for their property. They could as well call it .myData. It is not part of standard js Array type, but a name of their own custom property.

2 Likes

Tried that answer too and that works fine too.

Modified my project to have a button that downloads a CSV file. https://playcanvas.com/editor/scene/924158

Just to run off @LeXXik’s post. Taking this answer from that thread: https://stackoverflow.com/a/34043817

        var csv = convertArrayOfObjectsToCSV({
            data: stockData
        });

You can see here that they create a new object, with the property data that references stockData which is an array of objects to the function that converts it the CSV.

It works

Still (hmmm … JS sometimes :-/ )

How to make it with a push-structure instead?
I am trying to make the following work:


        var example_outCSVArray = [ ];
example_outCSVArray.push({name: 'steven', phone: '0000000'});
        example_outCSVArray.push({name: 'stn', phone: '00yt67600'});
        example_outCSVArray.push({name: 'en', phone: '04540'});
  • or by inducing by object:
  var valueToPush = {};
valueToPush.name = 'steven'; valueToPush.phone = '000000';
        example_outCSVArray.push(valueToPush);

Both gives me the err: “Uncaught TypeError: item[key].replace is not a function” as error at the line of:

result += '"' + item[key].replace('\"', "&quot;") + '"';

Tried both methods, both work in my example: https://playcanvas.com/editor/scene/924158

ps: approach of https://stackoverflow.com/questions/34089353/push-to-multidimensional-array-in-javascript

  • does not seem to help either …

var example_outCSVArray = {name:[], phone:[] };
example_outCSVArray.name.push(‘Steven’); example_outCSVArray.phone.push(‘0000’);
example_outCSVArray.name.push(‘Stn’); example_outCSVArray.phone.push(‘005675600’);
example_outCSVArray.name.push(‘Sn’); example_outCSVArray.phone.push(‘0003420’);

The CSV conversion code that I copied can’t handle non string values. So something like this:

        exampleArray.push({name: 'world', phone: 234146});

Breaks it as phone is not a string and therefore doesn’t have a replace function. This is pretty easy to fix though.