Reputation: 67
I have a chart created using chartjs and vuechartjs in my Vue project. Data will be passed in via mapGetters from my database. Data will change and the yAxes needs to be updated so that the ticks min and max and stepSize need to change corresponding to the available data being displayed. I wouldn't want my max to be 2500 with a step size of 250 when only displaying max data of 555. I want it to be closer to max 600 with stepSize of 50.
I read the documentation and it says to use chart.update(). I am trying to test this and it says that update cannot be read.
Error in v-on handler: "TypeError: Cannot read property 'update' of undefined"
Here is my code.
export default {
components: {
BarChart,
RoiCalculator
},
data() {
return {
data: [0,0,0,0,0,0,0,0,0,0,0],
maxFeedback: 0,
datacollection: null,
// Configure chart options here
options: {
tooltips: {
//Allows positioning of the tooltip to the event(mouse) position. Custom is the name of the position
//because that is the function created for Chart.Tooltip.positoners
position : 'custom',
callbacks: {
label: function(tooltipItem, data) {
var label = Math.floor(tooltipItem.yLabel*100)/100+" "+data.datasets[tooltipItem.datasetIndex].label;
return label;
}
}
},
maintainAspectRatio: false,
legend: {
//Hides the legend that would normally say NPS scores
display: false
},
// X and Y axes modified here
scales: {
// Allows you to customize the X axis
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Rating',
},
gridLines: {
display: false,
tickMarkLength: 0,
},
ticks: {
padding: 15,
showLabelBackdrop: false
}
}],
// Allows you to customize the Y axis
yAxes: [{
gridLines: {
tickMarkLength: 0,
},
ticks: {
padding: 15,
max: 500,
min: 0,
stepSize: 50
},
}]
},
},
}
},
mounted() {
this.populateFeedback();
},
computed: {
...mapGetters({
filteredFeedback: "initialFeedback"
}),
tid: function() {
return Spark.state.currentTeam.id;
} ,
},
watch: {
filteredFeedback: {
handler(){
this.loadData()
this.getMaxData()
this.resizeChart()
},
},
},
methods: {
...mapActions({
changeInitialFeedback: "changeInitialFeedback",
}),
updateChart(chart){
this.datacollection.datasets[0].data = [100, 200, 400, 600, 700, 1000, 120, 300, 305, 400, 555];
this.chartData.update();
},
loadData(){
this.datacollection = {
labels: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
datasets: [{
label: '',
data: this.sortData(),
backgroundColor: [
'rgb(242, 74, 99)',
'rgb(242, 74, 99)',
'rgb(242, 74, 99)',
'rgb(242, 74, 99)',
'rgb(242, 74, 99)',
'rgb(242, 74, 99)',
'rgb(242, 74, 99)',
'rgb(253, 205, 61)',
'rgb(253, 205, 61)',
'rgb(9, 198, 117)',
'rgb(9, 198, 117)',
],
}]
}
},
resizeChart(){
console.log(this.Chart)
console.log(this.options.scales.yAxes[0].ticks.stepSize,'options')
if(!this.maxFeedback <= 0 && !this.maxFeedback >=100){
this.options.scales.yAxes[0].ticks.max = 100
this.options.scales.yAxes[0].ticks.stepSize = 10
}
else if (this.maxFeedback <= 500){
this.options.scales.yAxes[0].ticks.max = 500
this.options.scales.yAxes[0].ticks.stepSize = 50
}
else (this.maxFeedback <= 2200)
this.options.scales.yAxes[0].ticks.max = 2500
this.options.scales.yAxes[0].ticks.stepSize = 250
},
getMaxData(){
const maxFB = Math.max.apply(Math, this.datacollection.datasets[0].data)
console.log(maxFB, 'hello')
this.maxFeedback = maxFB
},
sortData(){
//Filters through all our filtered feedback data and adds them to each rating
const output=[0,0,0,0,0,0,0,0,0,0,0]
this.filteredFeedback.forEach(function (e) {
output[e.nps_rating] += 1
}
);
return output
},
populateFeedback() {
axios
.get(`/api/metricsPage/all/` + this.tid)
.then(response => {
// Filtering out incomplete data
let filteredFeedback = response.data.feedbacks.filter(feedback => {
return feedback.nps_icon || feedback.has_comments;
});
filteredFeedback = filteredFeedback.map(feedback =>{
feedback.service_rating = Number(feedback.service_rating);
feedback.product_rating = Number(feedback.product_rating);
feedback.delivery_rating = Number(feedback.delivery_rating);
feedback.nps_rating = Number(feedback.nps_rating);
return feedback;
})
// vuex calls to set global state
this.changeInitialFeedback({ initialFeedback: filteredFeedback });
})
.catch(error => {
throw error;
});
},
}
}
</script>
<script>
// This file is what exports the chart used in the index
// Imports and determines type of chart (Line, Bar, etc.)
import { Bar } from 'vue-chartjs'
//Creates custom positioning for the positoning of the tooltip.
Chart.Tooltip.positioners.custom = function(elements, eventPosition) { //<-- custom is now the new option for the tooltip position
/** @type {Chart.Tooltip} */
var tooltip = this;
/* ... */
return {
x: eventPosition.x,
y: eventPosition.y
};
}
export default {
extends: Bar,
props: ['options', 'chartData'],
data() {
return{
chart: this.chartData
}
},
watch: {
//Renders the chart
chartData(){
this.renderChart(this.chartData, this.options)
}
},
}
</script>
I was expecting chart.update() to update but it keeps returning undefined.
Upvotes: 0
Views: 745
Reputation: 730
The first component you posted refers to this.chartData()
, however there is no chartData
property on that component. You can force an update by create a ref
, then accessing this.$refs.<yourref>.update()
within your update handler.
Upvotes: 1