First off, thanks for creating vue-chartsjs. I've been looking for a good, effective charting solution for Vue, and this looks like it's the perfect fit for my project.
I'm having a hard time getting a single-page vue component working with soil humidity sensor I'm creating. I have two relevant files, SensorChart.vue and HumidityChart.js.
I would like a graph of my soil measurements to be shown on screen. I am retrieving sensor data from an API endpoint, which returns a list of sensor reading objects.
The chart works as expected when I resize the browser, which I assume is triggering some sort of update() function.
But, when the browser is first loaded, the chart appears empty. In checking the Vue DevTools Chrome Extension, the data is loaded. Vue just isn't registering the component.
I've read your documentation on reactivity, but I'm not sure if that is this exactly the same thing as this issue. I don't need to update this after the data is retrieved from the API.
I've attached the full code below:
HumidityChart.js
import { Line, mixins } from 'vue-chartjs';
const { reactiveProp } = mixins;
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options'],
mounted() {
this.renderChart(this.chartData, { responsive: true, maintainAspectRatio: false });
},
};
SensorChart.vue
<template>
<div class="container">
<div v-if="gotSensorLog">
<line-chart :chart-data="dataCollection"></line-chart>
<button class="button" @click="addItem">Add Item</button>
</div>
</div>
</template>
<script>
import LineChart from '../components/HumidityChart.js';
import axios from 'axios';
export default {
components: {
LineChart
},
data () {
return {
gotSensorLog: false,
dataCollection: {
labels: [],
datasets: [
{
label: 'Light',
backgroundColor: '#D7F2C4',
data: [],
},
]
}
}
},
created() {
axios.get(`/api/sensorlog/`)
.then((response) => {
const logs = response.data;
logs.forEach((log) => {
this.dataCollection.datasets[0].data.push(log.light)
var date = new Date(log.created_at)
const month = date.getMonth() + 1;
const day = date.getDate();
const minutes = (date.getMinutes()<10?'0':'') + date.getMinutes()
const hours = date.getHours();
const year = date.getFullYear();
const full_date = `${month}-${day}-${year} ${hours}:${minutes}`
this.dataCollection.labels.push(full_date)
})
});
this.gotSensorLog = true;
},
}
</script>
<style>
</style>
Well... you have to move the this.gotSensorLog = true; into the then() statement.
Like mentioned in some other issues regarding this, API calls are asynchronous.
So you need to wait for the api response before rendering your chart. You should always use a state variable and v-if for the chart. So you can be sure that your data is there before your rendering your chart.
Thats kind of what you did there with this.gotSensorLog I guess. However you set the state outside the Promise, axios will return.
So the execution will look like this:
created() hookaxios.get() startinggotSensorLog = trueaxios.get() endingSo your are setting the variable before the api call finished.
https://codepen.io/apertureless/pen/eVoqzJ?editors=1010
Check out this pen. Click start and look in the console. You see the execution order.
So place the this.gotSensorLog = true inside your then() and you'll be fine :)
Oh man, I can't believe I didn't catch that :)
That fixed it. I'm not going to admit how much time I spent on that!
By the way, I love using ChartJS with vue. Thanks again for putting this together and for the quick response to my issue.
This issue is closed!
Most helpful comment
Well... you have to move the
this.gotSensorLog = true;into thethen()statement.Like mentioned in some other issues regarding this, API calls are asynchronous.
So you need to wait for the api response before rendering your chart. You should always use a state variable and
v-iffor the chart. So you can be sure that your data is there before your rendering your chart.Thats kind of what you did there with
this.gotSensorLogI guess. However you set the state outside the Promise, axios will return.So the execution will look like this:
created()hookaxios.get()startinggotSensorLog = trueaxios.get()endingSo your are setting the variable before the api call finished.
https://codepen.io/apertureless/pen/eVoqzJ?editors=1010
Check out this pen. Click start and look in the console. You see the execution order.
So place the
this.gotSensorLog = trueinside yourthen()and you'll be fine :)