Vue-chartjs: Reactivity of Options

Created on 8 May 2017  ·  10Comments  ·  Source: apertureless/vue-chartjs

I need to have Options be reactive so that it will update the title property. It does not appear to be watched in the mixin? No matter what I do below, the title will not re-render on the chart.

// lineChart.js
import { Line, mixins } from 'vue-chartjs'

export default Line.extend({
  mixins: [mixins.reactiveProp],
  props: ['chartData', 'options'],
  mounted () {
    this.renderChart(this.chartData, this.options)
  }
})
// Nevermind the inconsistency that the "bar" component is delivering a "line" :)
// chart component
<template lang="pug">
.columns
  .column.is-11.is-offset-1
    .card
      bar-chart(v-bind:chartData='chartData' 
                v-bind:options='chartOptions' 
                v-bind:height='340', v-bind:width='960' )
</template>



md5-891e9d135f1d388db18ea30b5309b3cf


Environment

  • vue.js version: 2.1.10
  • vue-chart.js version: 2.5.6
  • npm version: 3.10.3
☂ feature-request ❓ question

Most helpful comment

Hi @crholliday
Yeah the options are not reactive by default. But like @euledge pointed out, you can simply add a watcher by yourself.

You could try to call this._chart.update() which is the internal chart.js method to update the chart instance. However I am not sure if this will work with options.

If this is not working, calling renderChart() is the right way. But you should destroy the old instance before you do so. Because renderChart() creates a new chartjs instance. Which could lead to weird problems.

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

export default Line.extend({
  mixins: [mixins.reactiveProp],
  props: ['chartData', 'options'],
  watch: {
    'options': {
      handler (newOption, oldOption) {
        this._chart.destroy()
        this.renderChart(this.chartData, this.options)
      },
      deep: true
    }
  },
  mounted () {
    this.renderChart(this.chartData, this.options)
  }
})

I will see if I can implement it as a feature :v: so it will work out of the box

All 10 comments

I feel the same thing as you. Now I implement with the following way.
I hope it will be possible to watch options as mixins.reactiveProp too.

export default Line.extend({
  mixins: [mixins.reactiveProp],
  props: ['chartData', 'options'],
  watch: {
    'options': {
      handler(newOption, oldOption) {
        this.renderChart(this.chartData, this.options)
      },
      deep: true
    }
  }
});

Euledge, thank you very much for helping. Unfortunately, when I change my chart code to include the watch and subsequent renderChart(), it is affecting the size of the chart (it appears to be doubling the size of the chart on each subsequent re-render). My chart js now looks like this:

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

export default Line.extend({
  mixins: [mixins.reactiveProp],
  props: ['chartData', 'options'],
  watch: {
    'options': {
      handler (newOption, oldOption) {
        this.renderChart(this.chartData, this.options)
      },
      deep: true
    }
  },
  mounted () {
    this.renderChart(this.chartData, this.options)
  }
})

Did I misinterpret your changes?

Thanks!

Hi @crholliday
Yeah the options are not reactive by default. But like @euledge pointed out, you can simply add a watcher by yourself.

You could try to call this._chart.update() which is the internal chart.js method to update the chart instance. However I am not sure if this will work with options.

If this is not working, calling renderChart() is the right way. But you should destroy the old instance before you do so. Because renderChart() creates a new chartjs instance. Which could lead to weird problems.

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

export default Line.extend({
  mixins: [mixins.reactiveProp],
  props: ['chartData', 'options'],
  watch: {
    'options': {
      handler (newOption, oldOption) {
        this._chart.destroy()
        this.renderChart(this.chartData, this.options)
      },
      deep: true
    }
  },
  mounted () {
    this.renderChart(this.chartData, this.options)
  }
})

I will see if I can implement it as a feature :v: so it will work out of the box

Hi @crholliday
I omitted the mounted block in the code, because I wrote complex processing on that block.
It's right as you wrote in mounted()

@apertureless
Thank you for show me destroy() is necessary.

Thanks Euledge and Apertureless... it is working now.

I can confirm, calling again renderChart was too buggy.
destroying before was the right solution.
The only difference is, I had to change a line

this.$data._chart.destroy();

Yeah due to the changes in v3

this._chart is now this.$data._chart

When I update data in Vue form which Chart get the data nothing happens. Console logs nothing...

Vue.component('lineChartKw', {
  extends: VueChartJs.Bar,
  mixins: [mixins.reactiveProp],
  props: ['chartData'],
  watch: {
    'chartData': {
      handler (newOption, oldOption) {
        console.log('refresh watcher')
        this.$data._chart.destroy()
        this.renderChart(this.chartData,{
          responsive: true,
          maintainAspectRatio: true
        })
      },
      deep: true
    }
  },
  mounted() {
    if (this.chartData) {
      this.renderChart(
        this.chartData, {
          responsive: true,
          maintainAspectRatio: true
        })
    }
  }
});

This is how data looks (and I update only data in first datasets):

patterndatakw: {
        labels: ['Backend', 'Full Stack', 'Mobile/Embedded', 'Testing', 'Frontend', 'Dev Ops', 'Business Intelligence', 'IT Trainee', 'Project Management', 'Support', 'UX Designer', 'Business Analyst', 'Other'],
        datasets: [{
          label: 'Refair.me Profile ',
          backgroundColor: '#a84979',
          data: [0.05, 0.2, 0.1, 0.5, 0.2, 0.05, 0, 0, 0, 0, 0]
        }]
      }

For now it only works if I update whole patterndatakw.

@janswist

Well, but you are talking now about your data, right? Not about your options.
Because this issue is about the options.

There are a ton of other issues, regarding the reactivity of data.

First of all, you are importing the reactivity mixin but overwriting it in your local component. The mixin, will check of changes, and depending on the changes it will either update() the chart or do a complete rerender.

It depends on how you are updating your data.

http://vue-chartjs.org/#/home?id=limitations

There are some limitations in javascript and vue, how to detect changes and what the watcher can detect.

I think destroying the chart then render again is not a good behavior.
This should work as expected.

export default {
  extends: Line,
  props: ['chartData', 'options'],
  watch: {
    options: {
      handler() {
        this.$data._chart.options = this.options
        this.$data._chart.update()
      },
      deep: true
    }
  },
  mounted() {
    this.renderChart(this.chartData, this.options)
  }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Tirke picture Tirke  ·  4Comments

kurbar picture kurbar  ·  4Comments

timster picture timster  ·  5Comments

jacobmischka picture jacobmischka  ·  3Comments

humanismusic picture humanismusic  ·  3Comments