Reputation: 11
on Bar click event of first chart "config.categoriesChart" gets the console error "chart.js:10403 Uncaught TypeError: Cannot read property 'handleEvent' of undefined" enter image description here which diplayed as chart.legend.handleEvent(args.event);
The issue happens after destroy the First chart on the bar click Event of first chart.
But if I use $('#how_i_spend_canvas').replaceWith($('')); its working fine without destroy the chart. enter image description here
Please let me what is the issue?
All code in document.ready
let Chart = require('chart.js');/
let ChartDataLabels = require('chartjs-plugin-datalabels');
let config = window.MvpFE.globalConfiguration.howISpend;
let dataChart = window.dataHowISpendCharts;
let labels = dataChart.howISpendDataCatgories.map(function (e) {
return e.label;
});
let data = dataChart.howISpendDataCatgories.map(function (e) {
return e.data;
});
//Chart Axis's
let scales = {
x: {
ticks: {
font: {
size: config.size,
},
color: config.dataLabelsColor,
},
},
y: {
display: false,
}
};
//Chart legend
let plugins = {
legend: {
display: false,
},
tooltip: {
enabled: true,
},
};
//Chart Data Labels
let dataLabels = {
color: config.dataLabelsColor,
anchor: 'end',
align: 'top',
offset: 0,
formatter: function (value) {
//Include a dollar sign
return '$' + value.toLocaleString();
},
};
//chart data
let howISpendChartdata = {
labels: labels,
datasets: [{
data: data,
backgroundColor: config.catogriesBackgroundColor,
borderColor: config.catogriesBorderColor,
hoverBackgroundColor: config.unSelectedColor,
hoverBorderColor: config.unSelectedColor,
borderWidth: config.barWidth,
borderRadius: config.barRadius,
borderSkipped: 'false',
datalabels: dataLabels
}]
}
// Category heading label text will be from json data
let categoryLabel = "";
//Array to store the bar background colors.
const barColors = [];
//Code to draw Chart
var ctx = document.getElementById('how_i_spend_canvas').getContext('2d');
config.categoriesChart = new Chart(ctx, {
type: 'bar',
data: howISpendChartdata,
// Chart pulgins & Options
plugins: [ChartDataLabels],
options: {
responsive: true,
maintainAspectRatio: false,
aspectRatio: 2,
plugins: plugins,
scales: scales,
onClick: function (evt, element) {
if (element.length > 0) {
const categoriesChart = config.categoriesChart;
let activeBarIndex = element[0].index;
categoryLabel = categoriesChart.data.labels[activeBarIndex];
// destroy any chart instances that are created
if (categoriesChart instanceof Chart) {
categoriesChart.destroy();
}
//$('#how_i_spend_canvas').replaceWith($('<canvas id="SelectedCategory" height="400px"></canvas>')); //replace current canvas
// Code to draw Chart
config.monthlyChart = new Chart(ctx, {
type: 'bar',
data: howISpendChartdata,
plugins: [ChartDataLabels],
options: {
responsive: true,
maintainAspectRatio: false,
aspectRatio: 2,
plugins: plugins,
scales: scales,
onClick: function (e, activeElements) {
//get the colors for bars
if (activeElements.length > 0) { // check the element is selected
const monthlyChart = config.monthlyChart;
monthlyChart.options.animation.colors = false;
monthlyChart.update();
}
}
}
},
});
config.monthlyChart.render();
}
},
}
}); // document.Ready Ends()
Upvotes: 1
Views: 1171
Reputation: 31
I came accros the same issue, reason for the exception is: Inside the onclick event if you try to destroy the same chart, chart reference becomes null before the event callback function returns. And that's why exception is thrown. You can fix this by destroying the chart instance after the event callback is completed i.e. using setTimeout function you can destroy the chart after 100ms or so. you can do it like this:
options: {
onClick: function (evt, element) {
if (element.length > 0) {
const categoriesChart = config.categoriesChart;
let activeBarIndex = element[0].index;
categoryLabel = categoriesChart.data.labels[activeBarIndex];
setTimeout(() => {
// destroy any chart instances that are created
if (categoriesChart instanceof Chart) {
categoriesChart.destroy();
}
//$('#how_i_spend_canvas').replaceWith($('<canvas id="SelectedCategory" height="400px"></canvas>')); //replace current canvas
// Code to draw Chart
config.monthlyChart = new Chart(ctx, {
type: 'bar',
data: howISpendChartdata,
plugins: [ChartDataLabels],
options: {
responsive: true,
maintainAspectRatio: false,
aspectRatio: 2,
plugins: plugins,
scales: scales,
onClick: function (e, activeElements) {
//get the colors for bars
if (activeElements.length > 0) { // check the element is selected
const monthlyChart = config.monthlyChart;
monthlyChart.options.animation.colors = false;
monthlyChart.update();
}
}
}
});
config.monthlyChart.render();
}, 100);
}
}
}
Below is solution for anyone facing similar problem:
options: {
onClick: function (evt, element) {
// get the require data from click event
let chart = Chart.getChart(e.chart.canvas.id);
const points = chart.getElementsAtEventForMode(e, 'nearest', { intersect: true }, true);
if (points.length) {
const firstPoint = points[0];
const elementIndex = firstPoint.index;
const datasetIndex = firstPoint.datasetIndex;
const dataset = chart.data.datasets[datasetIndex];
const datasetFieldLabel = dataset.label;
const itemLabel = chart.data.labels[elementIndex];
const itemValue = dataset.data[elementIndex];
setTimeout(() => {
// destroy the chart
// Render another chart
}, 100);
}
}
}
Upvotes: 0
Reputation: 5716
WARNING: This solution makes sense only if you're not using the legend plugin or don't need to handle legend item click event.
In my case I was getting this error even though I disabled legend
plugin in chart options, like this:
plugins: {
legend: {
display: false
}
}
The error stopped happening after I filtered events handled by the legend plugin, like this:
plugins: {
legend: {
display: false,
events: [] // this line was the key
},
}
Upvotes: 0