Tick Twitch
Tick Twitch

Reputation: 566

Chart.js - Uncaught TypeError: Object.defineProperty called on non-object for multiple charts

I want to render multiple charts with same class name.The div with same class name contains canvas object.Most of the options are same but a few are different.I want to send them via data attributes.Everything is okay but when i am going to select canvas element on dom-object, it comes :

Uncaught TypeError: Object.defineProperty called on non-object

I dont know why it's happening.

Below is the html code

<td
    class ="crypt-marketcap-canvas"
    data-charts ="[65,59,81,81,56,55,40,80,90]" 
    data-bg = "d3f0df"
    data-border = "8cd8aa">
    <canvas />
</td>

and js codes are

var charts = document.getElementsByClassName("crypt-marketcap-canvas");

for( let chart of charts ){
  let data = chart.dataset.charts;
  // console.log(chart.dataset.charts);
  let bg = chart.dataset.bg;
  let border = chart.dataset.border;

  let canvas = chart.querySelector('canvas');
  // console.log(canvas);
  let ctx = canvas.getContext('2d');
  console.log(ctx);
  let lineChartData = {
    labels : ["1","2","3","4","5","6","7","8","9"],
    datasets : [
        {
            backgroundColor : '#' + bg,
            borderColor : '#' + border,
            data : data,
            bezierCurve : true
        }
    ]  
  }
  new Chart(ctx, { //Error is showing on this line
    type:"line",
    data:lineChartData,
    options:options
  });
}

Upvotes: 1

Views: 6376

Answers (1)

Antonio Laguna
Antonio Laguna

Reputation: 9290

Your issue here is that data is a string "[65,59,81,81,56,55,40,80,90]" which Chart can't understand.

If you do a JSON.parse it would work:

let data = JSON.parse(chart.dataset.charts);

That converts the data back to an array which, I guess, is your intention.

var charts = document.getElementsByClassName("crypt-marketcap-canvas");

for( let chart of charts ){
  let data = JSON.parse(chart.dataset.charts);
  // console.log(chart.dataset.charts);
  let bg = chart.dataset.bg;
  let border = chart.dataset.border;

  let canvas = chart.querySelector('canvas');
  let ctx = canvas.getContext('2d');
  let lineChartData = {
    labels : ["1","2","3","4","5","6","7","8","9"],
    datasets : [
        {
            backgroundColor : '#' + bg,
            borderColor : '#' + border,
            data : data,
            bezierCurve : true
        }
    ]  
  }
  new Chart(ctx, { //Error is showing on this line
    type:"line",
    data:lineChartData,
    options: {}
  });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>

<table>
  <tbody>
    <tr>
      <td
    class ="crypt-marketcap-canvas"
    data-charts ="[65,59,81,81,56,55,40,80,90]" 
    data-bg = "d3f0df"
    data-border = "8cd8aa">
    <canvas />
</td>
    </tr>
  </tbody>
  </table>

Extra

If you have any control on how data-charts is being written to the DOM I'd say avoid [ and just would do something like this:

<td
    class ="crypt-marketcap-canvas"
    data-charts ="65,59,81,81,56,55,40,80,90" 
    data-bg = "d3f0df"
    data-border = "8cd8aa">
    <canvas />
</td>

Then on your script: let data = chart.dataset.charts.split(','); leading to the same result.

Reason I recommend this is because JSON.parse can throw exceptions if something odd happens so you'd have to wrap within a try/catch block.

Upvotes: 2

Related Questions