As I mentioned in my title I would like to initialize a Chart.js chart with an api. I found tutorials but they mostly update the data after the page is rendered. I would like to update the chart before the page is rendered. So I directly see the initialized chart without a reload.
<template>
<h3>Stacked</h3>
<Chart type="bar" v-if="isReady" :data="stackedData" :options="stackedOptions"/>
</template>
<script>
import axios from "axios";
import {defineComponent, ref} from 'vue';
export default {
data() {
return {
isReady: false,
stackedData: {
labels: ['A', 'B', 'C', 'D'],
datasets: [{
type: 'bar',
label: 'Something',
backgroundColor: '#42A5F5',
data: this.list_all
}, {
type: 'bar',
label: 'Another',
backgroundColor: '#66BB6A',
data: this.list_intersection
}]
},
stackedOptions: {
tooltips: {
mode: 'index',
intersect: false
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
},
basicOptions: null,
//---------------------------------------------------
all:[]
list_intersection:[],
list_all:[]
}
},
beforeCreate() {
let apiKaderURL = 'http://localhost:4000/apiKader';
axios.get(apiKaderURL).then(res => {
this.all = res.data;
this.saveData()
this.isReady=true;
}).catch(error => {
console.log(error)
});
},
methods:{
saveData: function (){
for (var i in this.all){
if(this.all[i].id==='2' ){
this.list_all.push(this.all[i].someNumber)
}
if(this.all[i].id==='8'){
this.list_intersection.push(this.all[i].someNumber)
}
}
return this.list_all && this.list_intersection
}
}
}
</script>
I am simply trying to get values with axios, filter them and then return them back to the data property of the chart objects so it gets initialized with these values.
I thought, because I call beforeCreate
, it should work, because I initialize the values before rendering but the chart does not show any values.
I did also try to do it with vue-chartjs
but I think it is not really working with Vue 3 or I did something wrong.
How can I accomplish that? Thank you really much in advance.
I haven't worked with Chart.js before, but I read through Installation, Integration, and Usage documentation and came up with an example that might help you (Vue 2 with Vue CLI).
I used my App.vue SFC as the parent of the child chart component ChartTest.vue. In the parent, I simulated an API call delay using a 'setTimeout' call in the 'mounted' hook.
App.vue
<template>
<div id="app">
<chart-test v-if="dataReady" :chartData="chartData" />
</div>
</template>
<script>
import ChartTest from '@/components/ChartTest'
export default {
name: 'App',
components: {
ChartTest
},
data() {
return {
chartData: [12, 19, 3, 5, 2, 3],
dataReady: false
}
},
methods: {
getData() {
this.dataReady = true;
}
},
mounted() {
// Simulate API call
setTimeout(this.getData(), 2000);
}
}
</script>
ChartTest.vue
<template>
<div class="chart-test">
<h3>Chart Test</h3>
<canvas id="my-chart" width="400" height="400" ref="chartref"></canvas>
</div>
</template>
<script>
import Chart from 'chart.js';
export default {
data() {
return {
myChart: null
}
},
props: {
chartData: {
type: Array,
required: true
}
},
mounted() {
this.myChart = new Chart(this.$refs.chartref, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: this.chartData,
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>
The lifecycle hooks (like beforeCreate
, etc.) don't actually delay the subsequent component lifecycle steps, even when async, they just provide an entry point in which to run code.
Use a v-if
to delay the rendering of the chart until the data is ready. The v-if
acts like a watch
and won't render the chart at all until then. Use an isReady
variable which you will set when the data is finished saving:
<Chart type="bar" v-if="isReady" :data="stackedData" :options="stackedOptions"/>
data() {
return {
isReady: false,
...
}
}
axios.get(apiKaderURL).then(res => {
this.all = res.data;
this.saveData()
this.isReady = true; // Triggering the `v-if`
})
(Untested, but should work on principle)
Additionally, you can't set a data property from another data property using this
, it will be undefined
. You can just set them to null
:
data: this.list_all // Does nothing, can't use `this` like that
data: null // Change to this
So set it to null
and fix the saveData
method:
methods: {
saveData() {
const listAll = [];
const listIntersection = [];
for (var i in this.all){
if(this.all[i].id==='2' ){
listAll.push(this.all[i].someNumber)
}
if(this.all[i].id==='8'){
listIntersection.push(this.all[i].someNumber)
}
}
this.stackedData.datasets[0].data = listAll;
this.stackedData.datasets[1].data = listIntersection;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.