Vue-chartjs: Chart only rendering on window resize

Created on 4 Mar 2018  ยท  2Comments  ยท  Source: apertureless/vue-chartjs

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.

Expected Behavior

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.

Actual Behavior

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.

Here is a video of the issue.

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>

Environment

  • vue.js version: 2.0
  • vue-chart.js version: newest
  • npm version: newest
โ“ question

Most helpful comment

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() hook
  • axios.get() starting
  • gotSensorLog = true
  • axios.get() ending

So 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 :)

All 2 comments

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() hook
  • axios.get() starting
  • gotSensorLog = true
  • axios.get() ending

So 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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Sykomaniac picture Sykomaniac  ยท  3Comments

LeeLenaleee picture LeeLenaleee  ยท  3Comments

Scalpel78 picture Scalpel78  ยท  4Comments

jacobmischka picture jacobmischka  ยท  3Comments

egorzekov picture egorzekov  ยท  4Comments