I am attempting to make a vue with vue-chartjs. I have followed all the associated documentation with regards to re-rendering the chart when the chartData prop is updated. My chart will only update after i resize the browser window.
my parenttestchart.vue file:
<template>
<div>
<h1>Chart datacollection update test</h1>
<p>This component demonstrates fetching data from the server.</p>
<p v-if="!datacollection"><em>Loading...</em></p>
<b-form-select
v-model="testthingSelect.selected"
text="Select testthing"
variant="primary"
:options="testthingSelect.options"
:on-change="changetestthing"
class="m-md-2">
</b-form-select>
<test-chart v-cloak :chart-data="datacollection" :chart-option="options"></test-chart>
</div>
</template>
<script>
import TestChart from './TestChart'
export default {
components: {
TestChart
},
data() {
return {
yAxisValues: [],
datacollection: {},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: false
},
gridLines: {
display: true
}
}],
xAxes: [{
type: "date",
display:true,
gridLines: {
display: false
}
}]
},
legend: {
display: true
},
responsive: true,
maintainAspectRatio: false
},
testthingSelect: {
selected: "EIA/COAL",
disabled: false,
readonly: false,
visible: true,
color: "",
options: [
{
value: null,
text: 'Select a testthing'
},
{
value: "item1",
text: "item1"
},
{
value: "item1",
text: "item1"
},
{
value: "item1",
text: "item1"
}
]
}
}
},
methods: {
changetestthing: async function () {
try {
let response = await this.$http.get(url for my data);
this.datacollection.datasets = [];
this.datacollection.labels = [];
...required data transformations
this.$set(this.datacollection, "labels", labels);
this.$set(this.datacollection, "datasets", datasets);
// this.datacollection.labels = labels;
// this.datacollection.datasets = datasets;
} catch (error) {
console.log(error)
}
}
},
watch: {
'commoditySelect.selected': function () { this.changeCommodity(); }
},
async created() {
// ES2017 async/await syntax via babel-plugin-transform-async-to-generator
// TypeScript can also transpile async/await down to ES5
try {
let response = await this.$http.get(url for my data);
this.datacollection.datasets = [];
this.datacollection.labels = [];
...required data transformations
this.$set(this.datacollection, "labels", labels);
this.$set(this.datacollection, "datasets", datasets);
// this.datacollection.labels = labels;
// this.datacollection.datasets = datasets;
} catch (error) {
console.log(error)
}
} catch (error) {
console.log(error)
}
}
}
my TestChart.vue file
<script>
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
//Exporting this so it can be used in other components
export default {
extends: Line,
mixins: [reactiveProp],
props: ['chartData', 'options'],
mounted() {
this.renderChart(this.chartData, this.options)
}
}
</script>
So this is working in terms of selecting and changing the datacollection within the parent vue. Unless i resize the window though the chart does not re-render. When the parenttestchart.vue initially loads i am receiving the following error: 'Uncaught TypeError: Cannot read property 'transition' of null' . But this does not seem to effect anything, as resizing the window will render the initial display of the chart. Updating the data changetestthing method does update the datacollection (chartData) correctly but unless i resize the window it does not re-render.
How can I force the chart to re-render? How can i get a reference to the TestChart component in the parent?? this.TestChart is undefined. I'm only curious about getting the reference in case from the reference i can manually call 'renderChart' on it. thanks.
*** Update
I was able to get the chart to update with the following modifications:
I removed the following lines from the changetestthing method:
this.datacollection.datasets = null;
this.datacollection.labels = null;
And changed the datacollection value assignment statement to this:
this.datacollection = Object.assign({}, this.datacollection, { labels: labels, datasets: datasets });
I can't say for sure that this is the best practice. According to vue.js documentation (https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats)
new properties added to the object will not trigger changes. In such
cases, create a fresh object with properties from both the original
object and the mixin object
So I believe by not setting the datacollection.labels and .datasets properties to null and then using the Object.assign the changes are triggered. I'm still not sure why they weren't triggered using the mixins or manual watch. Any comments appreciated.