0

I'm trying to use a similar approach to this project where labels and datasets are defined in a child component with binds to props in the parent component but I'm not getting any results.

"Vue.js devtools" add-on shows that props contain data passed in the parent component however the initial console log show empty arrays:

loadData init
Array []
Array []

So due to the fact that "Chart.js does not provide a live update if you change the datasets" I tried reactiveProp mixin which throws the error below, most likely because I'm updating only a single dataset:

Error in callback for watcher "chartData": "TypeError: newData.datasets is undefined"

Questions:

  1. How the charts in this project from GitHub are updated if initially, bound arrays are empty and I don't see any related mixin or watcher?

  2. How to use vue-chartjs mixins to provide live updates in this case? I want to keep all the options and config in the chart component and just update the labels and datatsets.

components/LineChart.vue

<script>

import { Line, mixins } from 'vue-chartjs'

const { reactiveProp } = mixins

export default {
  extends: Line,
  //mixins: [reactiveProp],
  props: {
    chartData: {
      type: Array | Object,
      required: true
    },
    chartLabels: {
      type: Array,
      required: true
    }
  },
  data () {
    return {
      options: {
        responsive: true,
        maintainAspectRatio: false,
        legend: {display: false},
        scales: {
          xAxes: [{
            display: false,
            scaleLabel: {
              display: false,
              labelString: 'Date'
            }
          }],
          yAxes: [{
            stacked: false,
            display: true,
            scaleLabel: {
              display: false,
              labelString: 'Price'
            },
            ticks: {
              beginAtZero: false,
              reverse: false
            }
          }]
        }
      }
    }
  },
  mounted () {
    this.renderChart({
      labels: this.chartLabels,
      datasets: [{
        label: 'Data One',
        backgroundColor: '#18BC9C',
        fill: true,
        pointRadius: 0,
        borderColor: '#18BC9C',
        data: this.chartData,
      }]
    }, this.options)
  }
}

</script>

App.vue

<template>
  <div class="main">
    <line-chart :chart-data="systemUptimeData" :chart-labels="systemUptimeLabels"/>
  </div>
</template>

<script>

import LineChart from './components/LineChart'

export default {
  name: 'Test',
  components: {
    LineChart
  },
  data: () => {
    return {
      systemUptimeLabels: [],
      systemUptimeData: [],
    }
  },
  methods: {
    loadData () {
      // This method will fetch data from API
      console.log('loadData init', this.systemUptimeLabels, this.systemUptimeData)
      this.systemUptimeLabels = ['a', 'b', 'c']
      this.systemUptimeData = [1, 2, 3]
    }
  },
  mounted () {
    this.loadData()
  }
}
</script>

<style scoped>
.main {
  max-width: 800px;
  max-height: 600px;
  width: 100%;
  padding-right: 15px;
  padding-left: 15px;
  margin-right: auto;
  margin-left: auto;
}
</style>

1 Answer 1

1
  1. Well the reactivePropMixin will not work in your example. Because it will only work if you pass the whole chart.js data object as a prop. Not only the data array for one dataset. It is quite limited. However you can simply add an own watcher and then call this.$data._chart.update()

  2. The main problem with API requests is that they are async. So you component gets mounted, request the data and your chart gets rendered with no data, because your api call is maybe not finished at the time. Then it finishes, mutate your data and your chart will break. To prevent this it is a common practice to add a condition. In your promise or async call you need to define something like isLoaded and if you finished the api call you can set it to true. And then add a condition to your chart v-if="isLoaded" so your chart gets initially only rendered if you have your data from the API.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.