Chart.js: `Uncaught TypeError: Cannot read property 'length' of null` (vuejs + chart.js)

Created on 17 Dec 2016  Â·  17Comments  Â·  Source: chartjs/Chart.js

Hello,

I am trying to use Chart.js with vuejs. Unfortunately, I'm already blocked from trying out the "beginners" example'...

Here's my Vue Component:

<template>
  <canvas id="myChart" width="400" height="400"></canvas>
</template>

<script>
/*eslint-disable*/
import Chart from '../../node_modules/chart.js/src/Chart.js'
let ctx = document.getElementById("myChart")

var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3]
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});

export default {
  name: 'dashboard',
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  }
}
</script>

And the error I get:
Uncaught TypeError: Cannot read property 'length' of null

Most helpful comment

Oh I see, <canvas>...</canvas> need to be declared before <script>...</script>

:+1:

All 17 comments

Are you able to make a fiddle with this error so that we can debug?

The chart initialization should have been in mounted / the element was missing
I suggest you add a more meaningful debug error : element not found or chart element not found etc..

I have the same problem, how to you solve it ?

@HornKild read my last/previous comment. The error was due to the element not being present in the HTML when Chart.js was trying to attach the chart on it.

I'm very confused because I created a new HTML page with a clean code, no element missing, and still I get this error.

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<script>
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});
</script>
<canvas id="myChart" width="400" height="400"></canvas>

And the error :

Chart.min.js:14 Uncaught TypeError: Cannot read property 'length' of null
acquireContext @ Chart.min.js:14
t.Controller @ Chart.min.js:11
t @ Chart.min.js:12
(anonymous function) @ charts.html:4

What could be wrong with this ?

Thank you,

Oh I see, <canvas>...</canvas> need to be declared before <script>...</script>

:+1:

Hit the same issue and yes the <canvas> tag must preceed the <script>, but there needs to be better error message. Nowhere in the documentation does it mention that it's a strict requirement.

Same issue here expect I am dynamically creating everything does this mean that the canvas must be appended to the DOM before instantiating the Chart ?

@AKFourSeven you can't create a chart without a valid DOM reference (the canvas element must exist before constructing the chart), however the element doesn't need to be attached to the DOM (see #4591). That's a recent feature (v2.7), maybe you are not using the latest version.

Note: if you really need to import your scripts before your canvas element, you can still delay the chart creation until the DOM is fully loaded (jsfiddle):

<script>
window.addEventListener('load', function() {
  new Chart('chart', {
    type: 'line',
    data: // ...
  });
});
</script>
<canvas id="chart"></canvas>

Isn't there another way? this will prove to be very painful with my current code, the canvas and the chart both have to be loaded before the page is fully loaded, there is no two way around it.
Plus I have 5 different charts, which means all of them should be already in the DOM before I can create my Charts...
This does not seem ideal, I may have to find another solution...

Maybe I didn't understand your issue, but in all cases you can't create a chart without a canvas element (I'm open to any implementation suggestion to do differently). How about creating your canvas dynamically as well (jsfiddle)?:

function create_chart() {
    // Create a new canvas to receive the chart
    var canvas = document.createElement('canvas');

    // Attach the canvas wherever you want
    // Note: since 2.7, the canvas can be detached when creating the chart
    document.body.appendChild(canvas);

    // Create the chart on that canvas
    var chart = new Chart(canvas, { ... });
}

Actually I found the culprit, we have a legacy library: prototype (which I cannot simply trash) that is causing the issue.
When I add that one to your fiddle, it breaks your implementation : https://fiddle.jshell.net/m8w0yz4b/5/
So I will probably skip on the jump of version... Or find another brilliant idea.

Did you try to upgrade to prototype 1.7.3 (https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.3/prototype.min.js), seems to work fine with Chart.js 2.7 (fiddle).

Just tried that, well I will see if upgrading (or getting rid of the lib altogether is possible).
Thanks for all the help.

do not put the chart in created .....just put it in mounted .
it just about the timing.

do not put the chart in created .....just put it in mounted .
it just about the timing.

I understand this is due to the vue life cycle, right?
Can you explain why it works in mounted and not in created? 🤓

do not put the chart in created .....just put it in mounted .
it just about the timing.

I understand this is due to the vue life cycle, right?
Can you explain why it works in mounted and not in created?

Mounted triggered after first render but created triggered before the rendering.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

longboy picture longboy  Â·  3Comments

bytesnz picture bytesnz  Â·  3Comments

JAIOMP picture JAIOMP  Â·  3Comments

HeinPauwelyn picture HeinPauwelyn  Â·  3Comments

lizbanach picture lizbanach  Â·  3Comments