Reputation: 1871
I'm trying chart.js
with vue.js
.
I've a component called MessageGraph
that looks like this (the data etc is from the docs):
<template>
<canvas id="myChart" width="400" height="400"></canvas>
</template>
<script>
import Chart from 'chart.js';
export default {
created() {
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>
But I receive this error in my console:
app.c47f281….js:71222 [Vue warn]: Error in created hook:
(found in <MessageGraph> at /Users/Janssen/Code/forumv2/resources/assets/js/components/graph/MessageGraph.vue)
warn @ app.c47f281….js:71222
handleError @ app.c47f281….js:72107
callHook @ app.c47f281….js:72939
Vue._init @ app.c47f281….js:74420
VueComponent @ app.c47f281….js:74584
createComponentInstanceForVnode @ app.c47f281….js:73779
init @ app.c47f281….js:73587
createComponent @ app.c47f281….js:75318
createElm @ app.c47f281….js:75261
createChildren @ app.c47f281….js:75386
createElm @ app.c47f281….js:75294
createChildren @ app.c47f281….js:75386
createElm @ app.c47f281….js:75294
patch @ app.c47f281….js:75753
Vue._update @ app.c47f281….js:72697
updateComponent @ app.c47f281….js:72820
get @ app.c47f281….js:73131
Watcher @ app.c47f281….js:73114
mountComponent @ app.c47f281….js:72824
./node_modules/vue/dist/vue.common.js.Vue$3.$mount @ app.c47f281….js:77914
./node_modules/vue/dist/vue.common.js.Vue$3.$mount @ app.c47f281….js:79963
Vue._init @ app.c47f281….js:74430
Vue$3 @ app.c47f281….js:74511
./resources/assets/js/app.js @ app.c47f281….js:80091
__webpack_require__ @ app.c47f281….js:20
0 @ app.c47f281….js:80854
__webpack_require__ @ app.c47f281….js:20
(anonymous) @ app.c47f281….js:66
(anonymous) @ app.c47f281….js:69
app.c47f281….js:72111 TypeError: Cannot read property 'length' of null
at Object.acquireContext (app.c47f281….js:14468)
at new Chart.Controller (app.c47f281….js:7776)
at new Chart (app.c47f281….js:10193)
at VueComponent.created (app.c47f281….js:2106)
at callHook (app.c47f281….js:72937)
at VueComponent.Vue._init (app.c47f281….js:74420)
at new VueComponent (app.c47f281….js:74584)
at createComponentInstanceForVnode (app.c47f281….js:73779)
at init (app.c47f281….js:73587)
In my app.js I've added the component:
Vue.component('messageGraph', require('./components/graph/MessageGraph.vue'));
Then in my app.blade file I've this:
<message-graph></message-graph>
What could be the problem?
Upvotes: 1
Views: 1738
Reputation: 320
You are accessing the canvas element in the created()
hook, which is called before your template is attached to the DOM.
To solve your problem you need to put your code into the mounted()
hook of your component. But still, it is not guaranteed that the template is in document. So you have to use $vm.nextTick() to ensure the DOM is ready. (source).
Also, I recommend using vue's Child component refs, which is more vue-like than document.getElementById()
(it works too).
Vue.component('message-graph', {
template: '<canvas ref="chart" width="400" height="400"></canvas>',
mounted() {
this.$nextTick(() => {
let myChart = new Chart(this.$refs.chart, {
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
}
}]
}
}
})
})
}
})
let vue = new Vue({
el: '#app',
template: '<div class="myApp"><message-graph></message-graph></div>'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.js"></script>
<div id="app"></div>
Upvotes: 2