3👍
That is because VueJS uses virtual DOM and it updates the actual DOM in batches: what you’re providing your app is an inline template, which VueJS will parse, interpolate, and rewrite it to the DOM. Therefore if you initialise ChartJS first, it will lose the reference to the DOM element (it is either gone because of a race condition with VueJS, or it is quickly overwritten by Vue once it computes virtual DOM and outputs it to the actual DOM).
The reason why changing your markup worked is because now the element that ChartJS uses to mount and render the chart is no longer erased or manipulated by VueJS, as it is no longer part of the Vue app but resides outside of it in regular DOM.
In fact, the most parsimonious solution is to simply instantiate ChartJS in the mounted
hook of your VueJS app, and after waiting for the DOM to be ready, i.e.:
mounted: async function() {
// Wait for the DOM to be rendered after next tick
await this.$nextTick();
// Use ChartJS with the element that now exists in the DOM
const myChart = new Chart('chart-flow-rate', {
type: 'bar',
data: {
labels: ['4', '2'],
datasets: [{
data: [4, 2],
}]
}
});
}
In fact, I would go a step further and implore you to avoid using DOM query methods and take advantage of the ref
attribute and the $refs
instance property. In your template, update your markup to use refs:
<canvas ref="chart"></canvas>
Since ChartJS accepts an element as the first argument, you can simply access the element using this.$refs.canvas
:
const myChart = new Chart(this.$refs.chart, { ... })
See proof-of-concept below:
// Start VueJS
const Application = {
data() {
return {
name: "My Chart"
};
},
mounted: async function() {
await this.$nextTick();
// Use ChartJS
const myChart = new Chart(this.$refs.chart, {
type: 'bar',
data: {
labels: ['4', '2'],
datasets: [{
data: [4, 2],
}]
}
});
}
}
vm = Vue.createApp(Application).mount('#vue-app');
<script src="https://unpkg.com/vue@next"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.0/dist/chart.js"></script>
<main id="vue-app">
<p>{{ name }}</p>
<canvas ref="chart"></canvas>
</main>