0

This seems to be a promise error but when I console.log in my Chart class it works fine. Here is the relevant part of the Chart class:

createScales(){
    console.log(this.data); //this works fine, data is type 'object'.
    this.keynames = d3.scaleOrdinal();

    this.keynames.domain(Object.keys(this.data[0]).filter(function(key){
      console.log(key); //this works fine too, column keys are returned.
      return key !== 'date';
    }));

    this.keymap = this.keynames.domain().map(function(keyname) {
      return{
        name: keyname,
        values: this.data.map(function(d){ //here is the error
          return {
            date: d.date,
            key: +d[keyname]
          }
        })
      }
    });

I'm new to javascript and some terminology is still unfamiliar to me. Why is data undefined inside this.keymap but works just fine when logged outside?

This is the full traceback:

chart.js:46 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'data')
    at chart.js:46
    at Array.map (<anonymous>)
    at Chart.createScales (chart.js:43)
    at Chart.draw (chart.js:30)
    at Chart.setData (chart.js:116)
    at init (plot.js:15)
(anonymous) @ chart.js:46
createScales @ chart.js:43
draw @ chart.js:30
setData @ chart.js:116
init @ plot.js:15
Promise.then (async)
(anonymous) @ plot.js:12

This is how I'm passing my data to chart.js:

let getData = d3.csv('d1.csv', function(d){
                        //data returning stuff here, works fine 
                        }
                      }).then(init);

function init(data){
  chart.setData(data); //updates constructor with new data
}

As I previously stated, my data works fine when read from the Chart class. Does anyone know what's going on?

Bigboss01
  • 438
  • 6
  • 21
  • The problem is the `this.data` inside the `this.keynames.domain().map` callback. You've used a traditional function as the callback, so `this` is controlled by how `map` calls it (and `map` doesn't call it with anything specific, so in strict mode `this` is `undefined`). See the answers to the [linked question](this.data) (but TL;DR -- make that `map` callback an arrow function instead). (All three of the callbacks in that code -- the `filter` one and the two `map` ones -- could be arrow functions, but it's only that specific `this.keynames.domain().map` one that's the problem.) – T.J. Crowder Oct 12 '21 at 12:09
  • 1
    @T.J.Crowder Thank you!! Works great: ```this.keynames.domain(Object.keys(this.data[0]).filter(key => key!=='date')); this.keymap = this.keynames.domain().map(keyname => ({name: keyname, values: this.data.map(d => ({date: d.date, key: +d[keyname]}))}));``` I've been avoiding arrow functions because I didn't fully understand their applications but this was a very helpful practical example, and I appreciate your succinct explanation- I'll be checking out your book :) – Bigboss01 Oct 12 '21 at 12:28

0 Answers0