Search code examples
vue.jsbuttonvue-chartjs

Vue-chartjs chart update button with method parameter requires multiple clicks


I am trying to allow users to display different charts by sending the id of the chosen chart to the fillData method. There are several issues with the code as is. Once a chart is loaded it takes two clicks of the other button to load the new chart, even though the data is retrieved successfully by the get method. After page load, chart 1 loads if I click either button.

Here is the main component:

<template>
  <div class="small">
    <line-chart :chart-data="datacollection"></line-chart>
    <button @click="fillData(1)">Chart 1</button>
    <button @click="fillData(2)">Chart 2</button>
  </div>
</template>

<script>
  import LineChart from './ResultsChart.vue'

  export default {
    components: {
      LineChart
    },
    props: ['id'],
    data () {
      return {
        datacollection: null
      }
    },
    mounted (id) {

      this.fillData(id)
    },
    computed: {
    chartData: function() {
      return this.data;
    }
  },
    methods: {
      fillData (id=1) {

        this.datacollection = {
          labels: this.getDates(id),
          datasets: [
            {
              label: 'Data One',
              backgroundColor: '#f87979',
              data: this.getData(id)
            }
          ]
        }
        },

      getDates: function(id){
              axios.get('api/get_dates/' + id)
              .then(function (response) {
                 this.dates = response.data;
              }.bind(this));
              return this.dates;
            },
      getData: function(id){
              axios.get('api/get_results/' + id)
              .then(function (response) {
                 this.rdata = response.data;
              }.bind(this));
              return this.rdata;
            },     
      getStudents: function(){
              axios.get('/get_students')
              .then(function (response) {
                 this.students = response.data;
              }.bind(this));
              return students;
            },
      getCharts: function(){
              axios.get('/get_charts')
              .then(function (response) {
                 this.charts = response.data;
              }.bind(this));
              return charts;
            }, 

    }
  }
</script>

<style>
  .small {
    max-width: 600px;
    margin:  150px auto;
  }
</style>

and the Mixin:

<script>
  import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins

export default {
  extends: Line,
  mixins: [reactiveProp],
  props: ['options','chartData'],
  mounted () {
    // this.chartData is created in the mixin.
    // If you want to pass options please create a local options object
    this.renderChart( this.options)
  }
}

</script>

Any help appreciated. Thanks


Solution

  • After much casting about I found a solution that seems to work. I am new to both Chartjs and Vue, so I don't know if this is best practice. I moved the axios get requests inside the fillData function and updated the data inside the callback of the axios request.

    <template>
      <div class="small">
        <line-chart :chart-data="datacollection"></line-chart>
        <button v-model="chart_id" :value=1 @click="fillData(1)">Chart 1</button>
        <button v-model="chart_id" value=2 @click="fillData(2)">Chart 2</button>
      </div>
    </template>
    
    <script>
      import LineChart from './ResultsChart.vue'
    
      export default {
        components: {
          LineChart
        },
        data () {
          return {
            datacollection: null
          }
        },
        mounted () {
    
          this.fillData()
        },
    
        methods: {
    
          fillData (id=1) {
              axios.get('api/get_dates/' + id)
                  .then(function (response) {
                     this.dates = response.data;
    
                  axios.get('api/get_results/' + id)
                  .then(function (response) {
                     this.rdata = response.data; 
                     this.datacollection = {
              labels: this.dates,
              datasets: [
                {
                  label: 'Data One',
                  backgroundColor: '#f87979',
                  data: this.rdata,
    
                }
              ]
            }
                   }.bind(this))
    
    
    
                  }.bind(this));
    
            },
    
    
        }
      }
    </script>